dotnet/efcore · error · InvalidOperationException
The foreign keys on ' ' and on ' ' are both mapped to ' '…
Error message
The foreign keys {foreignKeyProperties1} on '{entityType1}' and {foreignKeyProperties2} on '{entityType2}' are both mapped to '{foreignKeyName}', but are declared on different tables ('{table1}' and '{table2}'). What it means
Two foreign keys resolve to the same constraint name in the database but their declaring entity types map to different tables, so they cannot share a single constraint. RelationalForeignKeyExtensions.AreCompatible throws DuplicateForeignKeyTableMismatch when GetColumnNames fails for either FK on the store object (i.e. they live on different tables).
Solutions
- Let EF auto-generate constraint names, or ensure any HasConstraintName override is unique per physical table.
- Inspect both foreign keys shown in the message and confirm whether they really should share a name (they should not, since they are on different tables).
- Rename one constraint so the database-level names diverge.
Example fix
// before
modelBuilder.Entity<Order>().HasOne(o => o.Customer).WithMany()
.HasForeignKey(o => o.CustomerId).HasConstraintName("FK_Customer");
modelBuilder.Entity<Invoice>().HasOne(i => i.Customer).WithMany()
.HasForeignKey(i => i.CustomerId).HasConstraintName("FK_Customer");
// after
modelBuilder.Entity<Invoice>().HasOne(i => i.Customer).WithMany()
.HasForeignKey(i => i.CustomerId).HasConstraintName("FK_Invoice_Customer"); Defensive patterns
Strategy: validation
Validate before calling
// Ensure no two FKs on different tables share a constraint name
var groups = modelBuilder.Model.GetEntityTypes()
.SelectMany(e => e.GetDeclaredForeignKeys())
.Where(fk => fk.GetConstraintName() is not null)
.GroupBy(fk => (fk.GetConstraintName(), fk.DeclaringEntityType.GetSchemaQualifiedTableName()));
foreach (var g in groups.Where(g => g.Count() > 1))
{
// Names must be unique per table — but here the conflict is across tables sharing a name
}
// Stronger: assert each constraint name maps to exactly one table
var nameToTables = modelBuilder.Model.GetEntityTypes()
.SelectMany(e => e.GetDeclaredForeignKeys())
.Where(fk => fk.GetMappedForeignKeys(StoreObjectIdentifier.Table(fk.DeclaringEntityType.GetTableName()!)).Any())
.GroupBy(fk => fk.GetConstraintName())
.Where(g => g.Select(fk => fk.DeclaringEntityType.GetSchemaQualifiedTableName()).Distinct().Count() > 1);
if (nameToTables.Any()) throw new InvalidOperationException("A FK constraint name is shared across different tables."); Prevention
- Avoid forcing HasConstraintName to the same value across different tables.
- Let EF auto-name constraints or include the table name in any override.
- Add a startup test asserting unique constraint names per physical table.
When it happens
Trigger: Two entities on different tables each have a foreign key whose computed name collides (because EF generates names from properties + principal); overriding HasConstraintName to the same value on FKs declared on different tables.
Common situations: Manually forcing the same constraint name across two unrelated FKs; TPT/split-table scenarios where two entity types accidentally resolve to the same FK name but on different tables; legacy naming overrides that no longer fit after a schema split.
Related errors
- The foreign keys on ' ' and on ' ' are both mapped to ' …
- The entity type ' ' was configured to use some stored…
- The foreign keys on ' ' and on ' ' are both mapped to ' …
- Both entity type ' ' and ' ' were configured to use ' '…
- Current value parameter
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/4ab1bb25646d6f2e.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs:44
bool shouldThrow)
{
var principalType = foreignKey.PrincipalKey.IsPrimaryKey()
? foreignKey.PrincipalEntityType
: foreignKey.PrincipalKey.DeclaringEntityType;
var principalTable = StoreObjectIdentifier.Create(principalType, storeObject.StoreObjectType);
var duplicatePrincipalType = duplicateForeignKey.PrincipalKey.IsPrimaryKey()
? duplicateForeignKey.PrincipalEntityType
: duplicateForeignKey.PrincipalKey.DeclaringEntityType;
var duplicatePrincipalTable = StoreObjectIdentifier.Create(duplicatePrincipalType, storeObject.StoreObjectType);
var columnNames = foreignKey.Properties.GetColumnNames(storeObject);
var duplicateColumnNames = duplicateForeignKey.Properties.GetColumnNames(storeObject);
if (columnNames is null
|| duplicateColumnNames is null)
{
return shouldThrow
? throw new InvalidOperationException(
RelationalStrings.DuplicateForeignKeyTableMismatch(
foreignKey.Properties.Format(),
foreignKey.DeclaringEntityType.DisplayName(),
duplicateForeignKey.Properties.Format(),
duplicateForeignKey.DeclaringEntityType.DisplayName(),
principalTable.HasValue
? foreignKey.GetConstraintName(storeObject, principalTable.Value)
: foreignKey.GetDefaultName(),
foreignKey.DeclaringEntityType.GetSchemaQualifiedTableName(),
duplicateForeignKey.DeclaringEntityType.GetSchemaQualifiedTableName()))
: false;
}
if (principalTable is null
|| duplicatePrincipalTable is null
|| principalTable != duplicatePrincipalTable
|| foreignKey.PrincipalKey.Properties.GetColumnNames(principalTable.Value)
is not { } principalColumnsView on GitHub (pinned to 3a2006ef56)