dotnet/efcore · error · InvalidOperationException
Both ' ' and ' ' are mapped to the table ' '. All the…
Error message
Both '{entityType}' and '{otherEntityType}' are mapped to the table '{table}'. All the entity types in a non-TPH hierarchy (one that doesn't have a discriminator) must be mapped to different tables. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information. What it means
Thrown inside ValidateNonTphMapping when two different entity types within the same non-TPH hierarchy resolve to the same Table StoreObjectIdentifier (collision detected via derivedTypes dictionary). In TPT/TPC every type must map to its own distinct table, so a clash is rejected.
Solutions
- Give each entity type a unique table name in the non-TPH hierarchy.
- Switch to TPH (UseTphMappingStrategy) if you genuinely want them all in one table.
- Remove explicit ToTable overrides that force the collision and let conventions assign distinct names.
Example fix
// before (TPT, clash)
modelBuilder.UseTptMappingStrategy();
modelBuilder.Entity<Customer>().ToTable("People");
modelBuilder.Entity<Vendor>().ToTable("People"); // throws 426
// after
modelBuilder.Entity<Customer>().ToTable("Customers");
modelBuilder.Entity<Vendor>().ToTable("Vendors"); Defensive patterns
Strategy: validation
Validate before calling
foreach (var root in modelBuilder.Model.GetEntityTypes().Where(t => t.BaseType == null))
{
var strategy = root.GetMappingStrategy();
if (strategy != RelationalAnnotationNames.TptMappingStrategy
&& strategy != RelationalAnnotationNames.TpcMappingStrategy) continue;
var tables = new HashSet<string>();
foreach (var et in root.GetDerivedTypesInclusive())
{
var so = StoreObjectIdentifier.Create(et, StoreObjectType.Table);
if (so != null && !tables.Add(so.Value.Name))
throw new InvalidOperationException($"Table '{so.Value.Name}' used by multiple types in {root.DisplayName()} hierarchy.");
}
} Prevention
- In TPT/TPC, give each type a unique ToTable name.
- If a shared table is intended, use TPH instead.
- Add a test that walks the hierarchy and asserts distinct table names per type.
When it happens
Trigger: Two types in a TPT/TPC hierarchy both call ToTable("SameName"), or default table-name conventions produce the same name for sibling types; sharing a table via explicit ToTable overrides in a non-TPH hierarchy.
Common situations: Manually mapping derived types to the same table while using TPT/TPC; rename/refactor that made two types collide on pluralization; trying to simulate TPH by forcing the same table under TPT.
Related errors
- Both ' ' and ' ' are mapped to the stored procedure ' '…
- Both ' ' and ' ' are mapped to the view ' '. All the entity…
- The entity type ' ' is not mapped, so by default the owned…
- The mapping strategy
- The mapping strategy
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/f258c440a713b4dc.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:2241
&& entityType.GetDerivedTypes().Any(derived => StoreObjectIdentifier.Create(derived, storeObjectType) != null))
{
throw new InvalidOperationException(
RelationalStrings.UnmappedNonTPHOwner(
entityType.DisplayName(),
unmappedOwnedType.FindOwnership()!.PrincipalToDependent?.Name,
unmappedOwnedType.DisplayName(),
storeObjectType));
}
continue;
}
if (derivedTypes.TryGetValue(storeObject.Value, out var otherType))
{
switch (storeObjectType)
{
case StoreObjectType.Table:
throw new InvalidOperationException(
RelationalStrings.NonTphTableClash(
entityType.DisplayName(), otherType.DisplayName(), storeObject.Value.DisplayName()));
case StoreObjectType.View:
throw new InvalidOperationException(
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)View on GitHub (pinned to 3a2006ef56)