dotnet/efcore · error · InvalidOperationException
The entity type '{dependentType}' is mapped to '{storeObject
Error message
The entity type '{dependentType}' is mapped to '{storeObject}'. However the principal entity type '{principalEntityType}' is also mapped to '{storeObject}' and it's using the TPC mapping strategy. Entity types in a TPC hierarchy can use table-sharing only if they have no derived types. What it means
In ValidateNonTphMapping, when the hierarchy is TPC, EF allows a dependent entity to share a table with its principal via a row-internal foreign key ONLY if the dependent has no derived types of its own. If a dependent that table-shares also has directly derived types, EF cannot keep the TPC 'one table per concrete type' guarantee and throws.
Source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:2264
RelationalStrings.NonTphViewClash(
entityType.DisplayName(), otherType.DisplayName(), storeObject.Value.DisplayName()));
case StoreObjectType.InsertStoredProcedure:
case StoreObjectType.DeleteStoredProcedure:
case StoreObjectType.UpdateStoredProcedure:
throw new InvalidOperationException(
RelationalStrings.NonTphStoredProcedureClash(
entityType.DisplayName(), otherType.DisplayName(), storeObject.Value.DisplayName()));
}
}
if (isTpc)
{
var rowInternalFk = entityType.FindDeclaredReferencingRowInternalForeignKeys(storeObject.Value)
.FirstOrDefault();
if (rowInternalFk != null
&& entityType.GetDirectlyDerivedTypes().Any())
{
throw new InvalidOperationException(
RelationalStrings.TpcTableSharing(
rowInternalFk.DeclaringEntityType.DisplayName(),
storeObject.Value.DisplayName(),
rowInternalFk.PrincipalEntityType.DisplayName()));
}
}
derivedTypes[storeObject.Value] = entityType;
}
var rootStoreObject = StoreObjectIdentifier.Create(rootEntityType, storeObjectType);
if (rootStoreObject == null)
{
return;
}
if (rootEntityType.FindRowInternalForeignKeys(rootStoreObject.Value).Any()
&& derivedTypes.Count > 1View on GitHub (pinned to dbf9771522)
Solutions
- Move the dependent to its own table so it no longer shares with the principal: modelBuilder.Entity<Dependent>().ToTable("Dependents").
- Remove inheritance from the dependent (collapse the derived types) so it remains a leaf shared type.
- Switch the hierarchy away from TPC (e.g. to TPT) if the shared-table-with-inheritance pattern is required.
Example fix
// before
modelBuilder.Entity<Order>().UseTpcMappingStrategy();
modelBuilder.Entity<OrderDetail>().HasBaseType<OrderDetailBase>().ToTable("Orders"); // shares + derives
// after
modelBuilder.Entity<OrderDetail>().HasBaseType<OrderDetailBase>().ToTable("OrderDetails"); Defensive patterns
Strategy: validation
Validate before calling
bool TpcSharedDependentsAreLeaves(DbContext context)
{
foreach (var root in context.Model.GetEntityTypes()
.Where(e => e.BaseType == null && e.GetMappingStrategy() == "TPC"))
{
foreach (var et in root.GetDerivedTypesInclusive())
{
var so = StoreObjectIdentifier.Create(et, StoreObjectType.Table);
if (so is null) continue;
bool sharesWithPrincipal = et.FindDeclaredReferencingRowInternalForeignKeys(so.Value).Any();
if (sharesWithPrincipal && et.GetDirectlyDerivedTypes().Any()) return false;
}
}
return true;
} Try / catch
try { _ = context.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("TPC", StringComparison.Ordinal) && ex.Message.Contains("table-sharing", StringComparison.Ordinal))
{
throw new InvalidOperationException("A table-shared dependent in a TPC hierarchy has derived types. Move it to its own table or remove inheritance from it.", ex);
} Prevention
- In TPC, never add inheritance to entities that share a table with a principal.
- Give owned/inline dependents their own tables before extending them with derived types.
- Consider TPT if shared-table hierarchies are unavoidable.
When it happens
Trigger: A dependent entity (typically an owned/inline type via row-internal FK) shares a table with its principal AND GetDirectlyDerivedTypes().Any() is true on it, while the root has TPC mapping strategy. Triggered when you mix table/owner sharing with TPC and then add an inheritance chain on the shared dependent.
Common situations: Adding a base+derived relationship to an owned type that was previously table-shared in a TPC hierarchy; converting an owned type to a hierarchy while keeping its ToTable equal to the principal's.
Related errors
- The entity type '{dependentType}' is mapped to '{storeObject
- The short name for '{entityType1}' is '{discriminatorValue}'
- Both '{entityType}' and '{otherEntityType}' are mapped to th
- Both '{entityType}' and '{otherEntityType}' are mapped to th
- Both '{entityType}' and '{otherEntityType}' are mapped to th
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/9dfaeea02cf7421c.
Report an issue: GitHub.