dotnet/efcore · error · InvalidOperationException
' ' is mapped to the table ' ' while ' ' is mapped to the…
Error message
'{entityType}' is mapped to the table '{table}' while '{otherEntityType}' is mapped to the table '{otherTable}'. Map all the entity types in the hierarchy to the same table, or remove the discriminator and map them all to different tables. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information. What it means
Thrown inside ValidateTphMapping when a derived entity type resolves to a different Table StoreObjectIdentifier than the root (entityId != rootId). TPH requires the entire hierarchy to share a single table, so any derived type mapped to another table breaks the invariant.
Solutions
- Remove the ToTable override on the derived type so it inherits the root's table.
- Switch the whole hierarchy to TPT (UseTptMappingStrategy) if different tables are intended.
- Map the root to the same table as the derived types so they all match.
Example fix
// before (TPH but derived type on different table)
modelBuilder.Entity<Person>().ToTable("People");
modelBuilder.Entity<Customer>().ToTable("Customers"); // throws 432
// after (intended different tables -> TPT)
modelBuilder.UseTptMappingStrategy();
modelBuilder.Entity<Person>().ToTable("People");
modelBuilder.Entity<Customer>().ToTable("Customers"); Defensive patterns
Strategy: validation
Validate before calling
foreach (var root in modelBuilder.Model.GetEntityTypes().Where(t => t.BaseType == null))
{
if (root.FindDiscriminatorProperty() == null) continue; // not TPH
var rootSo = StoreObjectIdentifier.Create(root, StoreObjectType.Table);
if (rootSo == null) continue;
foreach (var et in root.GetDerivedTypes())
{
var so = StoreObjectIdentifier.Create(et, StoreObjectType.Table);
if (so != null && so.Value != rootSo.Value)
throw new InvalidOperationException($"{et.DisplayName()} maps to {so.Value.DisplayName()} but root maps to {rootSo.Value.DisplayName()} (TPH).");
}
} Prevention
- In TPH, do not call ToTable on derived types.
- If different tables are needed, switch to TPT with UseTptMappingStrategy().
- Add a model test asserting all derived types share the root's table under TPH.
When it happens
Trigger: A TPH hierarchy where a derived type calls ToTable("OtherTable") or is otherwise mapped to a different table than the root; default convention overridden per type.
Common situations: Adding ToTable on a derived type while staying on TPH; partial migration to TPT that forgot UseTptMappingStrategy; view-backed read models pulled into a TPH hierarchy.
Related errors
- Both ' ' and ' ' are explicitly mapped to the stored…
- Both ' ' and ' ' are mapped to the table ' '. All the…
- ' ' is mapped to the database function ' ' while ' ' is…
- ' ' is mapped to the stored procedure ' ' while ' ' is…
- ' ' is mapped to the view ' ' while ' ' is mapped to the…
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/a26c1dd50aedfa71.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:2330
if (rootSproc != null)
{
var sproc = StoredProcedure.FindDeclaredStoredProcedure(entityType, storeObjectType);
if (sproc != null
&& sproc != rootSproc)
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureTphDuplicate(
entityType.DisplayName(), rootEntityType.DisplayName(), rootId?.DisplayName()));
}
}
continue;
}
switch (storeObjectType)
{
case StoreObjectType.Table:
throw new InvalidOperationException(
RelationalStrings.TphTableMismatch(
entityType.DisplayName(), entityId.Value.DisplayName(),
rootEntityType.DisplayName(), rootId?.DisplayName()));
case StoreObjectType.View:
throw new InvalidOperationException(
RelationalStrings.TphViewMismatch(
entityType.DisplayName(), entityId.Value.DisplayName(),
rootEntityType.DisplayName(), rootId?.DisplayName()));
case StoreObjectType.Function:
throw new InvalidOperationException(
RelationalStrings.TphDbFunctionMismatch(
entityType.DisplayName(), entityId.Value.DisplayName(),
rootEntityType.DisplayName(), rootId?.DisplayName()));
case StoreObjectType.InsertStoredProcedure:
case StoreObjectType.DeleteStoredProcedure:
case StoreObjectType.UpdateStoredProcedure:
throw new InvalidOperationException(
RelationalStrings.TphStoredProcedureMismatch(View on GitHub (pinned to 3a2006ef56)