E2086
Delphi Programming Language
Severity: MinorWhat Does This Error Mean?
E2086 means you are trying to use a type before its definition is complete. This usually happens in recursive type definitions — when a record or object type tries to include itself as a value (not a pointer). In Delphi, a type must be completely defined before it can be used as a value type. The fix is usually to use a pointer to the type (^TypeName) instead of the type itself, which allows forward pointer declarations.
Affected Models
- Delphi 2
- Delphi 7
- Delphi XE
- Delphi 10.x
- Delphi 11
- Delphi 12
- All modern Delphi versions
Common Causes
- A record type has a field of the same record type (recursive value type — impossible without pointers)
- Two types mutually reference each other as value types in the same type block
- Trying to use a class or record type in its own definition before the definition is finished
- Using a type before its declaration appears in the code (forgot to declare it first)
- Circular type dependencies that cannot be resolved without using pointers
How to Fix It
-
If a record needs to reference itself (like a linked list node), use a pointer type: instead of 'Next: TNode' (impossible), use 'Next: PNode' where PNode = ^TNode.
A value type cannot contain itself (it would be infinite in size). A pointer to the type is fine — a pointer is always a fixed size (4 or 8 bytes).
-
Declare a forward pointer type before the full record definition: type PNode = ^TNode; TNode = record Value: Integer; Next: PNode; end;
The pointer type PNode can be declared before TNode is complete — Delphi allows forward pointer declarations within a type block.
-
For mutually referencing types, declare both pointer types first, then both full types: type PTypeA = ^TTypeA; PTypeB = ^TTypeB; TTypeA = record B: PTypeB; end; TTypeB = record A: PTypeA; end;
This works because pointers are always a fixed size — the compiler does not need to know the full structure of TTypeA to know the size of a pointer to it.
-
For class types (objects), this problem usually does not occur because class variables in Delphi are always references (pointers under the hood). If using records, use pointer fields for recursive references.
Delphi classes work differently from records — a class variable is already a reference, so you can have TMyClass fields that reference other TMyClass instances.
-
Check that the type being used is declared before the point where it is used. If it is in a different unit, make sure that unit is in the uses clause.
E2086 can also appear if a type is used before its declaration in the same file — move the declaration earlier in the type section.
When to Call a Professional
E2086 is a compile-time error that requires understanding Delphi's type system. The fix almost always involves using a pointer to the type instead of the type itself. This is standard in linked list, tree, and graph data structures.
Frequently Asked Questions
Why can a pointer type be declared before the full type definition?
Because a pointer is always the same size — 4 bytes on 32-bit systems, 8 bytes on 64-bit systems — regardless of what it points to. The compiler does not need to know the full structure of TNode to know how big a PNode (pointer to TNode) is. This is why forward pointer declarations are allowed in Delphi's type block. The actual type must still be fully defined somewhere in the same type block.
What is a linked list in Delphi and why does it need pointers?
A linked list is a data structure where each item (node) holds a value and a reference to the next item. In Delphi, a record cannot contain a copy of itself (that would be infinite in size). But a record can contain a pointer to another record of the same type. Example: TNode = record Value: Integer; Next: ^TNode; end; — each node contains a pointer to the next node.
Is E2086 common in modern Delphi with classes?
Much less common with classes than with records. Delphi class variables are already reference types (pointers under the hood) — TMyClass is effectively a pointer to a TMyClass instance. So a class can easily have a field of its own class type. E2086 is most common when working with records that need recursive references — use pointer fields in that case.