Unfortunately, there is no RTTI generated for Generic parameters. The only way to discover the value of T in a Generic container like TList<T> is to get the TRttiType for the target field itself, call its ToString() method to get its class name as a string, and parse out the substring that is between the brackets. For example:
..., System.StrUtils, System.Rtti;
OpenBracket, CloseBracket: Integer;
s := Ctx.GetType(TTestClass).GetField('test_list').FieldType.ToString; // returns 'TList<System.string>'
OpenBracket := Pos('<', s);
CloseBracket := PosEx('>', s, OpenBracket+1);
s := Copy(s, OpenBracket+1, CloseBracket-OpenBracket-1); // returns 'System.string'
// if multiple Generic parameters are present, they will be separated by commas...
Once you have extracted the Generic parameter as a string, you can use TRttiContext.FindType() if you need to access the RTTI for that type.
With that said, the following code provides a bunch of RTTI helpers:
TRttiTypeHelper = class helper for TRttiType
function GetGenericArguments: TArray<TRttiType>;
Internally, GetGenericArguments() uses the same technique I mention above. With it, you can do this instead:
..., System.Rtti, DSharp.Core.Reflection;
arr := Ctx.GetType(TTestClass).GetField('test_list').FieldType.GetGenericArguments;
typ := arr; // returns RTTI for System.String
s := typ.ToString; // returns 'System.string'
Thanks for this solid reply, but before I accept it as a final answer, could you please explain to me how the .ToString() method of the TRttiType instance for the test_list field obviously has access to this information when it prints the full string that you advise me to manually parse? The correct answer would in that case seem to be that there does exist RTTI information about this, although it's not accessible through the defined Delphi RTTI methods?
Also, while researching this myself in parallel, I found the TRttiEnumerationType which seems to be very promising for my objective with its .UnderlyingType property. Could you (or anyone else) possibly comment on that? Unfortunately I'm currently having some other problems with that solution, as described in the following other question: stackoverflow.com/questions/28922600/
TRttiType.ToString() simply returns the value of the TRttiNamedObject.Name property. TRttiType overrides the virtual GetName() property getter to retrieve the type name from the System.TypInfo RTTI pointed to by the TRttiType.Handle property (eg: PTypeInfo(Handle)^.Name). That Name value is generated by the compiler and stored as-is in the RTTI of the actual TList<String> class (not the TList<T> class, which has no RTTI of its own because it is not a concrete class). Again, there is no RTTI (from either the System.Rtti or System.TypInfo unit) for the Generic arguments
An enum is based on different types (byte, word, integer) depending on the number of elements, and compiler options. UnderlyingType tells you the base type. That has absolutely nothing to do with this discussion about Generics RTTI. And no, the documentation does not contradict my statement, it agrees with it. TList<T> itself does not have its own RTTI, but TList<String> (a concrete instantiation of TList<T>) does. Information about Generic parameters and their types is not stored in an instantiated type's RTTI. You have to hunt for it manually, as I explained.