dotnet/efcore · error · InvalidOperationException
The keys {keyProperties1} on '{entityType1}' and {keyPropert
Error message
The keys {keyProperties1} on '{entityType1}' and {keyProperties2} on '{entityType2}' are both mapped to '{keyName}', but on different tables ('{table1}' and '{table2}'). What it means
Thrown by RelationalKeyExtensions.AreCompatible during model validation when two keys (PK or alternate) share the same key name but key.Properties.GetColumnNames(storeObject) returns null for at least one — meaning the key's properties do not resolve to columns on the store object the duplicate lives on. EF treats same-named keys as one physical constraint, so it refuses keys that do not share one concrete column set on one table.
Source
Thrown at src/EFCore.Relational/Metadata/Internal/RelationalKeyExtensions.cs:33
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static bool AreCompatible(
this IReadOnlyKey key,
IReadOnlyKey duplicateKey,
in StoreObjectIdentifier storeObject,
bool shouldThrow)
{
var columnNames = key.Properties.GetColumnNames(storeObject);
var duplicateColumnNames = duplicateKey.Properties.GetColumnNames(storeObject);
return columnNames == null
|| duplicateColumnNames == null
? shouldThrow
? throw new InvalidOperationException(
RelationalStrings.DuplicateKeyTableMismatch(
key.Properties.Format(),
key.DeclaringEntityType.DisplayName(),
duplicateKey.Properties.Format(),
duplicateKey.DeclaringEntityType.DisplayName(),
key.GetName(storeObject),
key.DeclaringEntityType.GetSchemaQualifiedTableName(),
duplicateKey.DeclaringEntityType.GetSchemaQualifiedTableName()))
: false
: columnNames.SequenceEqual(duplicateColumnNames)
|| (shouldThrow
? throw new InvalidOperationException(
RelationalStrings.DuplicateKeyColumnMismatch(
key.Properties.Format(),
key.DeclaringEntityType.DisplayName(),
duplicateKey.Properties.Format(),
duplicateKey.DeclaringEntityType.DisplayName(),
key.DeclaringEntityType.GetSchemaQualifiedTableName(),View on GitHub (pinned to dbf9771522)
Solutions
- Rename one key so each table/constraint has a distinct name, or remove the explicit key-name override.
- Ensure both entity types actually share the same table and that every key property resolves to a column on it (avoid JSON mapping for the colliding key).
- If one entity is JSON-mapped, do not give its key the same name as a table-mapped entity's key.
- Inspect key.Properties.GetColumnNames(storeObject) on both keys to see which returns null and why.
Example fix
// before
modelBuilder.Entity<Tenant>().HasAlternateKey(t => t.Code).HasName("AK_Code");
modelBuilder.Entity<Region>().HasAlternateKey(r => r.Code).HasName("AK_Code"); // different tables -> throws
// after
modelBuilder.Entity<Region>().HasAlternateKey(r => r.Code).HasName("AK_Region_Code"); Defensive patterns
Strategy: validation
Validate before calling
// Ensure each named key resolves columns on a single table
foreach (var et in model.GetEntityTypes())
{
foreach (var key in et.GetDeclaredKeys())
{
foreach (var mapping in et.GetTableMappings())
{
var so = StoreObjectIdentifier.Table(mapping.Table.Name, mapping.Table.Schema);
if (key.GetName(so) is string n
&& key.Properties.GetColumnNames(so) is null)
{
throw new InvalidOperationException($"Key '{n}' on {et.Name} does not resolve to columns on {so.DisplayName()}");
}
}
}
} Prevention
- Do not reuse key names across entity types on different tables.
- Avoid naming JSON-mapped entity keys the same as table-mapped entity keys.
- Add a model-validation test asserting no DuplicateKey* conflicts.
When it happens
Trigger: Lines 30-42 of RelationalKeyExtensions.cs: columnNames == null || duplicateColumnNames == null. Produced when HasKey/HasAlternateKey with GetName(storeObject) collides across entity types whose properties are not mapped to columns on the shared table (e.g. JSON-mapped entities at line 109, or TPT table mismatches).
Common situations: Two entity types configured with the same key name via the Name annotation but mapped to different tables; an entity mapped to JSON getting a key whose name collides with a table-mapped entity's key; TPT inheritance where a key name is reused across hierarchy tables.
Related errors
- The indexes {index1} on '{entityType1}' and {index2} on '{en
- The keys {keyProperties1} on '{entityType1}' and {keyPropert
- The type '{entityType}' is not mapped to the store object '{
- The property '{keyProperty}' cannot be configured as 'ValueG
- The key {keyProperties} on the entity type '{entityType}' ca
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/1ccc47234be4777d.
Report an issue: GitHub.