dotnet/efcore · error · InvalidOperationException

The short name for ' ' is ' ' which is the same for ' '…

Error message

The short name for '{entityType1}' is '{discriminatorValue}' which is the same for '{entityType2}'. Every concrete entity type in the hierarchy must have a unique short name. Either rename one of the types or call 'modelBuilder.Entity<TEntity>().Metadata.SetDiscriminatorValue("NewShortName")'.

What it means

Thrown inside ValidateDiscriminatorValues when two concrete derived types in a non-TPH hierarchy resolve to the same string discriminator value (the duplicate is found via discriminatorValues.TryGetValue(valueString, ...)). In TPT/TPC the discriminator value defaults to the entity short name (the simple type name), so two types sharing a short name collide.

Solutions

  1. Rename one of the colliding types so the simple names differ.
  2. Assign a unique discriminator value explicitly: modelBuilder.Entity<TEntity>().Metadata.SetDiscriminatorValue("NewShortName").
  3. Move one of the types into a different hierarchy or make it standalone.

Example fix

// before
namespace App.Admin { class User : Person {} }
namespace App.Store { class User : Person {} } // both short name "User" -> throws 423

// after
modelBuilder.Entity<App.Admin.User>().Metadata.SetDiscriminatorValue("AdminUser");
modelBuilder.Entity<App.Store.User>().Metadata.SetDiscriminatorValue("StoreUser");
Defensive patterns

Strategy: validation

Validate before calling

var byShortName = new Dictionary<string, List<string>>();
foreach (var entityType in modelBuilder.Model.GetEntityTypes()
    .Where(t => t.BaseType != null && t.ClrType.IsInstantiable()))
{
    var root = entityType.GetRootType();
    if (root.GetMappingStrategy() == RelationalAnnotationNames.TphMappingStrategy) continue;
    var value = entityType.GetDiscriminatorValue()?.ToString() ?? entityType.ShortName();
    byShortName.TryAdd(value, new());
    byShortName[value].Add(entityType.DisplayName());
}
var dup = byShortName.FirstOrDefault(kv => kv.Value.Count > 1);
if (dup.Key != null)
    throw new InvalidOperationException($"Duplicate short name '{dup.Key}': {string.Join(", ", dup.Value)}");

Prevention

When it happens

Trigger: Two concrete entity types in the same hierarchy have identical simple names (e.g. NamespaceA.User and NamespaceB.User both derive from Person), or two types are explicitly assigned the same discriminator value via SetDiscriminatorValue.

Common situations: Cross-namespace name collisions; generated/DTO types with reused names; bulk import of entities where short names repeat; forgetting that the discriminator value is the type name by default.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/a625818103e96275. Report an issue: GitHub.

Appendix: source

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

                    ValidateDiscriminatorValues(complexProperty.ComplexType);
                }

                var discriminatorValue = derivedType.GetDiscriminatorValue();
                if (!derivedType.ClrType.IsInstantiable()
                    || discriminatorValue is null)
                {
                    continue;
                }

                if (discriminatorValue is not string valueString)
                {
                    throw new InvalidOperationException(
                        RelationalStrings.NonTphDiscriminatorValueNotString(discriminatorValue, derivedType.DisplayName()));
                }

                if (discriminatorValues.TryGetValue(valueString, out var duplicateEntityType))
                {
                    throw new InvalidOperationException(
                        RelationalStrings.EntityShortNameNotUnique(
                            derivedType.Name, discriminatorValue, duplicateEntityType.Name));
                }

                discriminatorValues[valueString] = derivedType;
            }
        }
    }

    /// <summary>
    ///     Validates the key value generation is valid.
    /// </summary>
    /// <param name="key">The key.</param>
    /// <param name="logger">The logger to use.</param>
    protected virtual void ValidateValueGeneration(
        IKey key,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
    {

View on GitHub (pinned to 3a2006ef56)