dotnet/efcore · error · InvalidOperationException

The foreign keys {foreignKeyProperties1} on '{entityType1}'

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

Thrown by RelationalForeignKeyExtensions.AreCompatible when two foreign keys resolve to the same constraint name but their declaring entity types map to different tables. EF cannot create one database FK constraint spanning two different dependent tables, so it rejects the conflict during relational model validation.

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 { } principalColumns

View on GitHub (pinned to dbf9771522)

Solutions

  1. Set distinct HasConstraintName values on the colliding foreign keys so they do not collapse to one name.
  2. Ensure the two entity types that should share a constraint actually map to the same dependent table (table splitting/TPH) if that was the intent.
  3. Adjust table mapping so the FKs land on the same table if they are meant to be one constraint.
  4. Audit all foreign keys whose GetConstraintName is identical across different tables.

Example fix

// before
modelBuilder.Entity<Post>().HasOne(p => p.Blog).WithMany()
    .HasForeignKey(p => p.BlogId).HasConstraintName("FK_BlogRef");
modelBuilder.Entity<Comment>().HasOne(c => c.Blog).WithMany()
    .HasForeignKey(c => c.BlogId).HasConstraintName("FK_BlogRef");
// Posts & Comments are on different tables -> mismatch

// after
modelBuilder.Entity<Post>().HasOne(p => p.Blog).WithMany()
    .HasForeignKey(p => p.BlogId).HasConstraintName("FK_Post_Blog");
modelBuilder.Entity<Comment>().HasOne(c => c.Blog).WithMany()
    .HasForeignKey(c => c.BlogId).HasConstraintName("FK_Comment_Blog");
Defensive patterns

Strategy: validation

Validate before calling

// Detect FK name collisions across different tables before validation
var groups = modelBuilder.Model.GetEntityTypes()
    .SelectMany(t => t.GetForeignKeys())
    .Where(fk => fk.IsConstrained)
    .GroupBy(fk => fk.GetConstraintName());
foreach (var g in groups.Where(g => g.Select(fk => fk.DeclaringEntityType.GetSchemaQualifiedTableName()).Distinct().Count() > 1))
    throw new InvalidOperationException($"FK name {g.Key} on different tables.");

Prevention

When it happens

Trigger: Two entity types each define a foreign key whose generated/explicit constraint name collides, but the entity types are mapped to different physical tables. Triggered when EnsureRelationalModel runs compatibility checks with shouldThrow=true.

Common situations: Default FK name generation produces the same name for unrelated entity types mapped to separate tables (e.g. both FK_Blogs_Posts_Id). Custom HasConstraintName strings reused across types. Renaming a table after FKs were configured.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/4ab1bb25646d6f2e. Report an issue: GitHub.