Why shouldn't it work? The for in loop calls GetEnumerator, with self being nil. GetEnumerator then calls:
Result := TFPGListEnumeratorSpec.Create(Self);
Just passing self (nil) over to the TFPGListEnumerator<T>.Create, which does not touch FList until the first call to the MoveNext. The call to MoveNext then would immediately return false, causing Current to never be queried and thereby never try to access the list.
Also GetEnumerator is not virtual, so it's completely fine to call it with nil