Summary
Doctrine's inheritance mapping (Single Table Inheritance, Class Table Inheritance, Mapped Superclasses) introduces subtle configuration pitfalls and silent performance traps that are hard to catch during development. Doctrine Doctor currently has very limited coverage in this area (only DuplicatePrivateFieldInHierarchyAnalyzer and FinalEntityAnalyzer).
This issue proposes 10 new analyzers dedicated to inheritance mapping problems, organized by category.
Integrity Analyzers
1. MissingDiscriminatorMapEntryAnalyzer
Detect concrete subclasses that are not listed in the #[DiscriminatorMap]. When omitted, Doctrine auto-generates the map at runtime, which is explicitly documented as "very expensive computation-wise" since the mapping driver has to scan and load all known classes. Beyond performance, a missing entry can cause silent bugs where persisted entities cannot be hydrated back to the correct type.
2. SingleTableInheritanceNullableColumnAnalyzer
In Single Table Inheritance, columns belonging to subclasses must be nullable because rows of sibling types will not populate them. A NOT NULL constraint on a subclass-specific column will cause insert failures for other subtypes. This is a common schema mistake that only surfaces at runtime with the right data.
3. InheritanceTypeOnNonRootEntityAnalyzer
#[InheritanceType], #[DiscriminatorColumn], and #[DiscriminatorMap] must be declared on the root entity of the hierarchy. Placing them on a subclass is a misconfiguration that Doctrine may silently ignore or that causes undefined behavior. This analyzer would flag the mistake early.
4. MappedSuperclassAsTargetEntityAnalyzer
A Mapped Superclass cannot be used as targetEntity in associations because it has no table of its own and is not queryable. This is a hard constraint in Doctrine that produces a runtime MappingException. Catching it statically saves debugging time.
5. MappedSuperclassOneToManyAnalyzer
OneToMany associations on a Mapped Superclass are not supported because the "many" side needs to hold a foreign key pointing to a concrete table. This only works with ResolveTargetEntityListener and a single subclass. The analyzer would flag OneToMany on mapped superclasses and suggest using entity inheritance (STI/CTI) or restructuring the relationship.
6. MissingDiscriminatorColumnAnalyzer
Detect an entity with #[InheritanceType] but no #[DiscriminatorColumn]. While Doctrine falls back to a default column name, relying on implicit defaults makes the schema harder to understand and can conflict with existing columns.
7. OverrideOnInheritanceEntityAnalyzer
#[AttributeOverride] and #[AssociationOverride] are only supported on entities extending a Mapped Superclass. Using them within an entity inheritance hierarchy (STI/CTI) is explicitly not supported and can produce incorrect mappings silently.
Performance Analyzers
8. ClassTableInheritanceDepthAnalyzer
Class Table Inheritance requires a JOIN per level in the hierarchy for every polymorphic query. A hierarchy deeper than 2-3 levels can cause significant query performance degradation. This analyzer would warn when the hierarchy depth exceeds a configurable threshold.
9. PolymorphicAssociationEagerLoadAnalyzer
When a ManyToOne or OneToOne association targets an entity that is the root of an inheritance hierarchy (not a leaf), Doctrine cannot create a proxy because the concrete type is unknown until query time. This forces eager loading of the associated entity, which can propagate transitively to its own relationships. This is a common and silent performance trap that should be flagged with a recommendation to target leaf entities when possible.
10. SingleTableInheritanceTooManySubclassesAnalyzer
When a STI hierarchy grows to many subclasses with distinct columns, the single table becomes wide and sparse (most columns NULL for most rows). This degrades storage efficiency, index effectiveness, and query readability. The analyzer would warn above a configurable threshold of subclasses or nullable columns.
Priority
Ordered by impact and frequency of the underlying problem:
| Priority |
Analyzer |
Why |
| 1 |
PolymorphicAssociationEagerLoadAnalyzer |
Silent perf trap, very common, hard to diagnose |
| 2 |
MappedSuperclassAsTargetEntityAnalyzer |
Guaranteed runtime error, easy to catch statically |
| 3 |
SingleTableInheritanceNullableColumnAnalyzer |
Frequent schema bug, only surfaces with specific data |
| 4 |
MissingDiscriminatorMapEntryAnalyzer |
Hidden perf cost + potential hydration bugs |
| 5 |
MappedSuperclassOneToManyAnalyzer |
Hard Doctrine limitation, confusing error message |
| 6 |
InheritanceTypeOnNonRootEntityAnalyzer |
Silent misconfiguration |
| 7 |
OverrideOnInheritanceEntityAnalyzer |
Explicitly unsupported, silently broken |
| 8 |
MissingDiscriminatorColumnAnalyzer |
Implicit default, low severity |
| 9 |
ClassTableInheritanceDepthAnalyzer |
Perf degrades gradually, threshold-based |
| 10 |
SingleTableInheritanceTooManySubclassesAnalyzer |
Perf degrades gradually, threshold-based |
References
Summary
Doctrine's inheritance mapping (Single Table Inheritance, Class Table Inheritance, Mapped Superclasses) introduces subtle configuration pitfalls and silent performance traps that are hard to catch during development. Doctrine Doctor currently has very limited coverage in this area (only
DuplicatePrivateFieldInHierarchyAnalyzerandFinalEntityAnalyzer).This issue proposes 10 new analyzers dedicated to inheritance mapping problems, organized by category.
Integrity Analyzers
1.
MissingDiscriminatorMapEntryAnalyzerDetect concrete subclasses that are not listed in the
#[DiscriminatorMap]. When omitted, Doctrine auto-generates the map at runtime, which is explicitly documented as "very expensive computation-wise" since the mapping driver has to scan and load all known classes. Beyond performance, a missing entry can cause silent bugs where persisted entities cannot be hydrated back to the correct type.2.
SingleTableInheritanceNullableColumnAnalyzerIn Single Table Inheritance, columns belonging to subclasses must be nullable because rows of sibling types will not populate them. A
NOT NULLconstraint on a subclass-specific column will cause insert failures for other subtypes. This is a common schema mistake that only surfaces at runtime with the right data.3.
InheritanceTypeOnNonRootEntityAnalyzer#[InheritanceType],#[DiscriminatorColumn], and#[DiscriminatorMap]must be declared on the root entity of the hierarchy. Placing them on a subclass is a misconfiguration that Doctrine may silently ignore or that causes undefined behavior. This analyzer would flag the mistake early.4.
MappedSuperclassAsTargetEntityAnalyzerA Mapped Superclass cannot be used as
targetEntityin associations because it has no table of its own and is not queryable. This is a hard constraint in Doctrine that produces a runtimeMappingException. Catching it statically saves debugging time.5.
MappedSuperclassOneToManyAnalyzerOneToMany associations on a Mapped Superclass are not supported because the "many" side needs to hold a foreign key pointing to a concrete table. This only works with
ResolveTargetEntityListenerand a single subclass. The analyzer would flag OneToMany on mapped superclasses and suggest using entity inheritance (STI/CTI) or restructuring the relationship.6.
MissingDiscriminatorColumnAnalyzerDetect an entity with
#[InheritanceType]but no#[DiscriminatorColumn]. While Doctrine falls back to a default column name, relying on implicit defaults makes the schema harder to understand and can conflict with existing columns.7.
OverrideOnInheritanceEntityAnalyzer#[AttributeOverride]and#[AssociationOverride]are only supported on entities extending a Mapped Superclass. Using them within an entity inheritance hierarchy (STI/CTI) is explicitly not supported and can produce incorrect mappings silently.Performance Analyzers
8.
ClassTableInheritanceDepthAnalyzerClass Table Inheritance requires a JOIN per level in the hierarchy for every polymorphic query. A hierarchy deeper than 2-3 levels can cause significant query performance degradation. This analyzer would warn when the hierarchy depth exceeds a configurable threshold.
9.
PolymorphicAssociationEagerLoadAnalyzerWhen a ManyToOne or OneToOne association targets an entity that is the root of an inheritance hierarchy (not a leaf), Doctrine cannot create a proxy because the concrete type is unknown until query time. This forces eager loading of the associated entity, which can propagate transitively to its own relationships. This is a common and silent performance trap that should be flagged with a recommendation to target leaf entities when possible.
10.
SingleTableInheritanceTooManySubclassesAnalyzerWhen a STI hierarchy grows to many subclasses with distinct columns, the single table becomes wide and sparse (most columns NULL for most rows). This degrades storage efficiency, index effectiveness, and query readability. The analyzer would warn above a configurable threshold of subclasses or nullable columns.
Priority
Ordered by impact and frequency of the underlying problem:
PolymorphicAssociationEagerLoadAnalyzerMappedSuperclassAsTargetEntityAnalyzerSingleTableInheritanceNullableColumnAnalyzerMissingDiscriminatorMapEntryAnalyzerMappedSuperclassOneToManyAnalyzerInheritanceTypeOnNonRootEntityAnalyzerOverrideOnInheritanceEntityAnalyzerMissingDiscriminatorColumnAnalyzerClassTableInheritanceDepthAnalyzerSingleTableInheritanceTooManySubclassesAnalyzerReferences
DuplicatePrivateFieldInHierarchyAnalyzer,FinalEntityAnalyzer