dotnet/efcore · error · InvalidOperationException

The discriminator value for '{entityType1}' is '{discriminat

Error message

The discriminator value for '{entityType1}' is '{discriminatorValue}' which is the same for '{entityType2}'. Every concrete entity type mapped to the container '{container}' must have a unique discriminator value.

What it means

Every concrete entity type mapped to a shared container must have a unique discriminator value. CosmosModelValidator throws InvalidOperationException via CosmosStrings.DuplicateDiscriminatorValue when two types resolve to the same discriminator value, since Cosmos could not then tell their documents apart.

Source

Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:212

            }

            if (entityType.ClrType.IsInstantiable()
                && entityType.GetContainingPropertyName() == null)
            {
                if (entityType.FindDiscriminatorProperty() == null)
                {
                    throw new InvalidOperationException(CosmosStrings.NoDiscriminatorProperty(entityType.DisplayName(), container));
                }

                var discriminatorValue = entityType.GetDiscriminatorValue();
                if (discriminatorValue == null)
                {
                    throw new InvalidOperationException(CosmosStrings.NoDiscriminatorValue(entityType.DisplayName(), container));
                }

                if (discriminatorValues.TryGetValue(discriminatorValue, out var duplicateEntityType))
                {
                    throw new InvalidOperationException(
                        CosmosStrings.DuplicateDiscriminatorValue(
                            entityType.DisplayName(),
                            discriminatorValue,
                            duplicateEntityType.DisplayName(),
                            container));
                }

                discriminatorValues[discriminatorValue] = entityType;

                var currentIsDiscriminatorMappingComplete = entityType.GetIsDiscriminatorMappingComplete();
                if (isDiscriminatorMappingComplete == null)
                {
                    isDiscriminatorMappingComplete = currentIsDiscriminatorMappingComplete;
                }
                else if (currentIsDiscriminatorMappingComplete != isDiscriminatorMappingComplete)
                {
                    throw new InvalidOperationException(
                        CosmosStrings.IsDiscriminatorMappingCompleteMismatch(

View on GitHub (pinned to dbf9771522)

Solutions

  1. Give each concrete entity type a distinct discriminator value.
  2. Audit all .HasValue calls (and defaults) per shared container to ensure uniqueness.

Example fix

// before (both use "pet")
modelBuilder.Entity<Cat>().HasDiscriminator(c => c.Kind).HasValue("pet");
modelBuilder.Entity<Dog>().HasDiscriminator(d => d.Kind).HasValue("pet");

// after (unique values)
modelBuilder.Entity<Cat>().HasDiscriminator(c => c.Kind).HasValue("cat");
modelBuilder.Entity<Dog>().HasDiscriminator(d => d.Kind).HasValue("dog");
Defensive patterns

Strategy: validation

Validate before calling

// Discriminator values must be unique within a container.
var byContainer = modelBuilder.Model.GetEntityTypes()
    .Where(e => e.FindPrimaryKey() != null && e.GetContainer() != null && e.ClrType.IsInstantiable())
    .GroupBy(e => e.GetContainer());
foreach (var g in byContainer.Where(g => g.Count() > 1))
{
    var dups = g.GroupBy(e => e.GetDiscriminatorValue()).Where(x => x.Count() > 1);
    if (dups.Any())
        throw new InvalidOperationException($"Duplicate discriminator value(s) in {g.Key}.");
}

Try / catch

try { context.Database.EnsureCreated(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("unique discriminator value"))
{ throw new InvalidOperationException("Give each type a distinct discriminator value.", ex); }

Prevention

When it happens

Trigger: Calling .HasValue("X") on two different concrete entity types mapped to the same container; inheriting a default value that collides; reusing a literal across types.

Common situations: Copy-paste of discriminator values when adding a new type; both types defaulting to the same short name string; merging two hierarchies into one container.

Related errors


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