diff --git a/.gitattributes b/.gitattributes
index 1d8993f072..69bd4a29e6 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -8607,6 +8607,7 @@ tests/webtbs/tw10425.pp svneol=native#text/plain
 tests/webtbs/tw1044.pp svneol=native#text/plain
 tests/webtbs/tw10454.pp svneol=native#text/plain
 tests/webtbs/tw1046.pp svneol=native#text/plain
+tests/webtbs/tw10482.pp svneol=native#text/plain
 tests/webtbs/tw10489.pp svneol=native#text/plain
 tests/webtbs/tw10492.pp svneol=native#text/plain
 tests/webtbs/tw10493.pp svneol=native#text/plain
diff --git a/rtl/objpas/classes/classesh.inc b/rtl/objpas/classes/classesh.inc
index 1e79a88528..1b9d59e4b0 100644
--- a/rtl/objpas/classes/classesh.inc
+++ b/rtl/objpas/classes/classesh.inc
@@ -902,7 +902,7 @@ type
   TValueType = (vaNull, vaList, vaInt8, vaInt16, vaInt32, vaExtended,
     vaString, vaIdent, vaFalse, vaTrue, vaBinary, vaSet, vaLString,
     vaNil, vaCollection, vaSingle, vaCurrency, vaDate, vaWString, vaInt64,
-    vaUTF8String, vaUString);
+    vaUTF8String, vaUString, vaVariant);
 
   TFilerFlag = (ffInherited, ffChildPos, ffInline);
   TFilerFlags = set of TFilerFlag;
@@ -1123,6 +1123,7 @@ type
     procedure ReadListBegin;
     procedure ReadListEnd;
     function ReadRootComponent(ARoot: TComponent): TComponent;
+    function ReadVariant: tvardata;
     function ReadString: string;
     function ReadWideString: WideString;
     function ReadUnicodeString: UnicodeString;
@@ -1299,6 +1300,7 @@ type
     procedure WriteString(const Value: string);
     procedure WriteWideString(const Value: WideString);
     procedure WriteUnicodeString(const Value: UnicodeString);
+    procedure WriteVariant(const VarValue: tvardata);
     property RootAncestor: TComponent read FRootAncestor write FRootAncestor;
     property OnFindAncestor: TFindAncestorEvent read FOnFindAncestor write FOnFindAncestor;
     property OnWriteMethodProperty: TWriteMethodPropertyEvent read FOnWriteMethodProperty write FOnWriteMethodProperty;
diff --git a/rtl/objpas/classes/reader.inc b/rtl/objpas/classes/reader.inc
index b5e705ee3a..d62dc64f6f 100644
--- a/rtl/objpas/classes/reader.inc
+++ b/rtl/objpas/classes/reader.inc
@@ -307,10 +307,10 @@ var
   i: Integer;
 begin
   case StringType of
-   vaLString,vaUTF8String:
-     i:=ReadDWord;
-  else
-  //vaString:
+    vaLString, vaUTF8String:
+      i:=ReadDWord;
+    else
+    //vaString:
       begin
         Read(b, 1);
         i := b;
@@ -1075,6 +1075,76 @@ begin
   CheckValue(vaNull);
 end;
 
+function TReader.ReadVariant: tvardata;
+type
+  tcurrec = record
+    i: int64;
+  end;
+begin
+  if not Assigned(VarClearProc) then
+    raise EReadError.Create(SErrNoVariantSupport);
+
+  VarClearProc(Result);
+  Read(Result.vtype,sizeof(Result.vtype));
+
+  case Result.vtype of
+    varEmpty,
+    varNull:
+      ;
+    { all integer sizes must be split for big endian systems }
+    varShortInt:
+      begin
+        Result.vShortInt:=ReadInteger;
+      end;
+    varSmallInt:
+      begin
+        Result.vSmallInt:=ReadInteger;
+      end;
+    varInteger:
+      begin
+        Result.vInteger:=ReadInteger;
+      end;
+    varInt64,varQWord:
+      begin
+        Result.vInt64:=ReadInt64;
+      end;
+    varBoolean:
+      begin
+        Result.vBoolean:=ReadBoolean;
+      end;
+    varCurrency:
+      begin
+        { avoid implicit value conversion by the compiler }
+        Result.vCurrency:=Currency(tcurrec(ReadInt64));
+      end;
+{$ifndef fpunone}
+    varSingle:
+      begin
+        Result.vSingle:=ReadSingle;
+      end;
+    varDouble:
+      begin
+        Result.vDouble:=ReadFloat;
+      end;
+    varDate:
+      begin
+        Result.vDate:=ReadFloat;
+      end;
+{$endif fpunone}
+    varOlestr:
+      begin
+        WideString(Pointer(Result.volestr)):=ReadWideString;
+      end;
+    varString:
+      begin
+        Ansistring(Result.vstring):=ReadWideString;
+      end;
+    else
+      raise EReadError.CreateFmt(SUnsupportedPropertyVariantType, [Ord(Result.vtype)]);
+  end;
+end;
+
+
 procedure TReader.ReadProperty(AInstance: TPersistent);
 var
   Path: String;
@@ -1191,6 +1261,7 @@ var
   Method: TMethod;
   Handled: Boolean;
   TmpStr: String;
+  VarTemp: tvardata;
 begin
   if not Assigned(PPropInfo(PropInfo)^.SetProc) then
     raise EReadError.Create(SReadOnlyProperty);
@@ -1260,7 +1331,12 @@ begin
       SetUnicodeStrProp(Instance,PropInfo,ReadUnicodeString);
     tkWString:
       SetWideStrProp(Instance,PropInfo,ReadWideString);
-    {!!!: tkVariant}
+    tkVariant:
+      begin
+        { can't use variant() typecast, pulls in variant unit }
+        VarTemp:=ReadVariant;
+        SetVariantProp(Instance,PropInfo,PVariant(@VarTemp)^);
+      end;
     tkClass:
       case FDriver.NextValue of
         vaNil:
@@ -1400,9 +1476,9 @@ begin
   StringType := FDriver.ReadValue;
   if StringType in [vaString, vaLString,vaUTF8String] then
     begin
-    Result := FDriver.ReadString(StringType);
-    if (StringType=vaUTF8String) then
-      Result:=utf8Decode(Result);
+      Result := FDriver.ReadString(StringType);
+      if (StringType=vaUTF8String) then
+        Result:=utf8Decode(Result);
     end
   else if StringType in [vaWString] then
     Result:= FDriver.ReadWidestring
diff --git a/rtl/objpas/classes/writer.inc b/rtl/objpas/classes/writer.inc
index 7aad4ec33d..99bb12d86e 100644
--- a/rtl/objpas/classes/writer.inc
+++ b/rtl/objpas/classes/writer.inc
@@ -720,6 +720,75 @@ begin
   Driver.WriteInteger(Value);
 end;
 
+procedure TWriter.WriteVariant(const VarValue: tvardata);
+type
+  tcurrec = record
+    i: int64;
+  end;
+var
+  vtype: tvartype;
+begin
+  vtype:=VarValue.vtype;
+  Write(ord(vtype),sizeof(vtype));
+  case vtype of
+    varEmpty,
+    varNull:
+      ;
+    { all integer sizes must be split for big endian systems }
+    varShortInt:
+      begin
+        WriteInteger(VarValue.vshortint);
+      end;
+    varSmallInt:
+      begin
+        WriteInteger(VarValue.vsmallint);
+      end;
+    varInteger:
+      begin
+        WriteInteger(VarValue.vinteger);
+      end;
+    varInt64,varQWord:
+      begin
+        WriteInteger(int64(VarValue.vint64));
+      end;
+    varBoolean:
+      begin
+        WriteBoolean(VarValue.vboolean);
+      end;
+    varCurrency:
+      begin
+        { write as int64, because on non-x86 a floating point register does
+          not have enough precision to hold the entire range of currency
+        }
+        WriteInteger(tcurrec(VarValue.vcurrency).i);
+      end;
+{$ifndef fpunone}
+    varSingle:
+      begin
+        WriteSingle(VarValue.vsingle);
+      end;
+    varDouble:
+      begin
+        WriteFloat(VarValue.vdouble);
+      end;
+    varDate:
+      begin
+        WriteFloat(VarValue.vdate);
+      end;
+{$endif fpunone}
+    varOleStr:
+      begin
+        WriteWideString(widestring(pointer(VarValue.volestr)));
+      end;
+    varString:
+      begin
+        WriteWideString(AnsiString(VarValue.vstring));
+      end;
+    else
+      raise EWriteError.CreateFmt(SUnsupportedPropertyVariantType, [Ord(VarValue.vtype)]);
+  end;
+end;
+
 procedure TWriter.WriteListBegin;
 begin
   Driver.BeginList;
@@ -746,6 +815,7 @@ begin
   Instance.DefineProperties(Self);
 end;
 
+
 procedure TWriter.WriteProperty(Instance: TPersistent; PropInfo: Pointer);
 var
   HasAncestor: Boolean;
@@ -767,6 +837,7 @@ var
   SavedAncestor: TPersistent;
   SavedPropPath, Name: String;
   Int64Value, DefInt64Value: Int64;
+  VarValue, DefVarValue : tvardata;
   BoolValue, DefBoolValue: boolean;
   Handled: Boolean;
 
@@ -918,7 +989,24 @@ begin
           Driver.EndProperty;
         end;
       end;
-  {!!!: tkVariant:}
+    tkVariant:
+      begin
+        if not assigned(VarClearProc) then
+          raise EWriteError.Create(SErrNoVariantSupport);
+
+        VarValue := tvardata(GetVariantProp(Instance, PropInfo));
+        if HasAncestor then
+          DefVarValue := tvardata(GetVariantProp(Ancestor, PropInfo))
+        else
+          VarClearProc(DefVarValue);
+
+        if (CompareByte(VarValue,DefVarValue,sizeof(VarValue)) <> 0) then
+          begin
+            Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
+            WriteVariant(VarValue);
+            Driver.EndProperty;
+          end;
+      end;
     tkClass:
       begin
         ObjValue := TObject(GetObjectProp(Instance, PropInfo));
diff --git a/tests/webtbs/tw10482.pp b/tests/webtbs/tw10482.pp
new file mode 100644
index 0000000000..790ac850e5
--- /dev/null
+++ b/tests/webtbs/tw10482.pp
@@ -0,0 +1,100 @@
+program fpctest4;
+{$ifdef fpc}
+{$mode delphi}
+{$endif fpc}
+uses
+{$ifdef unix}
+  cwstring,
+{$endif}
+  Classes,sysutils,variants,typinfo;
+
+type
+   TTestClass=class(TComponent)
+   private
+     fV1,fV2,fV3:variant;
+     procedure SetV2(const v:variant);
+   published
+     property V1:Variant read fV1 write fV1;
+     property V2:Variant read fV2 write SetV2;
+     property V3:Variant read fV3 write fV3;
+   end;
+	
+const
+   {$ifdef fpc}
+   ws:WideString=#$43f#$440#$438#$432#$435#$442', '#$43f#$440#$44B#$432#$456#$442#$430#$43d#$44c#$43d#$435' - pr'#$fc'fung spa'#$df' gut';
+   {$else}
+   ws:WideString='ÔË‚ÂÚ, Ô˚‚≥ڇ̸Ì - prufung spa'#$df' gut';
+   {$endif}
+
+procedure TTestClass.SetV2(const v:variant);
+begin
+  fV2:=v;
+  writeln('Set V2');
+end;
+
+var tc:TTestClass;
+    f:TStream;
+    vv:variant;
+    ff : TFileStream;
+begin
+
+   RegisterClasses([TTestClass]);
+
+
+   tc:=TTestClass.Create(nil);
+   tc.v1:=123.45;
+   tc.v2:='Hello world';
+   tc.v3:=ws;
+
+   vv:=GetVariantProp(tc,'V2');
+   if vv<>Null then
+     begin
+       if (vv<>'Hello world') then
+         halt(1);
+       writeln('got=',vv);
+     end
+   else
+     halt(2);
+
+
+   SetVariantProp(tc,'V1',333.333);
+
+   vv:=GetVariantProp(tc,'V1');
+   if vv<>Null then
+     begin
+       if (vv<>333.333) then
+         halt(3);
+       writeln('got=',vv);
+     end
+   else
+     halt(4);
+
+   f:=TMemoryStream.Create;
+   f.WriteComponent(tc); // store it
+
+   ff:=TFileStream.Create('tw19482.str',fmCreate);
+   ff.WriteComponent(tc); // store it
+   ff.Free;
+
+   tc.Free; // kill it
+
+   f.free;
+
+   f:=TFileStream.Create('tw19482.str',fmOpenRead);
+
+   tc:=TTestClass(f.ReadComponent(nil));
+
+   writeln('v1=',tc.v1);
+   writeln('v2=',tc.v2);
+   writeln('v3=',tc.v3);
+   if (tc.v1<>333.333) then
+     halt(5);
+   if (tc.v2<>'Hello world') then
+     halt(6);
+   if (tc.v3<>ws) then
+     halt(7);
+
+   f.Free;
+
+   DeleteFile('tw19482.str')
+end.