dotnet/efcore · error · InvalidOperationException

'{entityType1}.{property1}' and '{entityType2}.{property2}'

Error message

'{entityType1}.{property1}' and '{entityType2}.{property2}' are both mapped to column '{columnName}' in '{table}', but the properties are contained within the same hierarchy. All properties on an entity type must be mapped to different columns.

What it means

Two properties declared within the same inheritance hierarchy (one type is assignable from the other) cannot map to the same column on the same store object, because EF would not know which property a column value belongs to and the generated SQL/migrations would conflict. The validator at line 1506-1517 throws DuplicateColumnNameSameHierarchy when the duplicate column is found and the two declaring types are in the same hierarchy (the IsAssignableFrom checks succeed).

Source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:1509

            foreach (var property in structuralType.GetDeclaredProperties())
            {
                var columnName = property.GetColumnName(storeObject);
                if (columnName == null)
                {
                    continue;
                }

                missingConcurrencyTokens?.Remove(columnName);
                if (!propertyMappings.TryGetValue(columnName, out var duplicateProperty))
                {
                    propertyMappings[columnName] = property;
                    continue;
                }

                if (property.DeclaringType.IsAssignableFrom(duplicateProperty.DeclaringType)
                    || duplicateProperty.DeclaringType.IsAssignableFrom(property.DeclaringType))
                {
                    throw new InvalidOperationException(
                        RelationalStrings.DuplicateColumnNameSameHierarchy(
                            duplicateProperty.DeclaringType.DisplayName(),
                            duplicateProperty.Name,
                            property.DeclaringType.DisplayName(),
                            property.Name,
                            columnName,
                            storeObject.DisplayName()));
                }

                this.ValidateCompatible(property, duplicateProperty, columnName, storeObject, logger);
            }

            foreach (var complexProperty in structuralType.GetDeclaredComplexProperties())
            {
                ValidateCompatible(complexProperty.ComplexType, storeObject, propertyMappings, missingConcurrencyTokens, logger);
            }
        }
    }

View on GitHub (pinned to dbf9771522)

Solutions

  1. Rename one of the properties' column via .HasColumnName("<distinct>") so they no longer collide.
  2. If the column is meant to be shared, hoist the property up to the common base type so a single declared property maps to it.
  3. Remove the duplicate property if it is redundant.

Example fix

// before: BaseShape and derived Circle both have a property mapped to 'Radius'
//         on the same TPH table 'Shapes'
modelBuilder.Entity<BaseShape>().Property(b => b.Size).HasColumnName("Radius");
modelBuilder.Entity<Circle>().Property(c => c.Radius).HasColumnName("Radius");

// after
modelBuilder.Entity<BaseShape>().Property(b => b.Size).HasColumnName("Size");
modelBuilder.Entity<Circle>().Property(c => c.Radius).HasColumnName("Radius");
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    var table = et.GetTableName();
    if (table == null) continue;
    var storeObj = StoreObjectIdentifier.Table(table, et.GetSchema());
    var colToTypes = new Dictionary<string, List<(IProperty P, ITypeBase Decl)>>();
    foreach (var type in modelBuilder.Model.GetEntityTypes().Where(e => e.GetTableName() == table))
    {
        foreach (var p in type.GetProperties())
        {
            var col = p.GetColumnName(storeObj);
            if (col == null) continue;
            if (!colToTypes.ContainsKey(col)) colToTypes[col] = new();
            colToTypes[col].Add((p, p.DeclaringType));
        }
    }
    foreach (var (col, list) in colToTypes)
    {
        for (int i = 0; i < list.Count; i++)
            for (int j = i + 1; j < list.Count; j++)
            {
                var a = list[i]; var b = list[j];
                if (a.Decl.IsAssignableFrom(b.Decl) || b.Decl.IsAssignableFrom(a.Decl))
                    throw new InvalidOperationException(
                        $"Column '{col}' on table '{table}' mapped by two properties in same hierarchy: "
                        + $"{a.P.DeclaringType.DisplayName()}.{a.P.Name} and {b.P.DeclaringType.DisplayName()}.{b.P.Name}");
            }
    }
}

Prevention

When it happens

Trigger: In a TPH hierarchy, two sibling or ancestor/descendant entity types each declare a property that maps to the same column name on the same table. Triggered during ValidateSharedColumnsCompatibility's property-mapping walk.

Common situations: Two derived types accidentally using the same column name (e.g. both have a 'Notes' property); a base type property and a derived type property colliding after a rename; complex type properties whose names collide with owner properties.

Related errors


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