Hmm, what are you trying to achieve?

Testing in FPC in Delphi mode (just removed FastMM and compiled with "fpc -Mdelphi -gh a.pas", -gh adds memory leak checking) the code works. It should also work with Delphi, at least non-.net versions, as basic class implementation is the same there (as in all OOP languages). However, it works only by accident, as far as I see.

Reason: you create in TClass1.AddIt an instance of class TClass1. But later you want to cast it to class TClass2, which is simpy an invalid cast... The fact that it works, without introducing any memory leaks or access violations, is only an coincidence, a result of how compilers implement classes and a result of the fact that TClass2 does not introduce any new variables and does not introduce any new virtual methods.

But you're doing something inherently wrong, without any guarantee that it will always work... Changing unchecked cast "TClass2(C.AddIt())" to a checked cast "C.AddIt() as TClass2" reports "Invalid type cast", showing that the cast is wrong.

If you really need to cast C.AddIt result to a TClass2, you should just create TClass2 inside TClass1.AddIt. Like

[pascal]
........ { replacing with dots unchanged code }

type
{ Forward reference only, TClass2 wil be declared later. }
TClass2 = class;

TClass1 = class(TObject)
.......
function AddIt(): TClass2;
.......
end;

TClass2 = class(TClass1)
......

.........

function TClass1.AddIt: TClass2;
begin
Result := TClass2.Create('blah');
FList.Add(Result)
end;

............

var
C: TClass1;
begin
C := TClass1.Create();
try
C.X := 3.14;
with C.AddIt() do
begin
X := 5.25;
WriteVal();
end;
finally
FreeAndNil(C);
end;

readln;
end.
[/pascal]

Now the cast is even not needed, and all is correct.