dotnet/efcore · error · InvalidOperationException
The specified discriminator value '{value}' for '{entityType
Error message
The specified discriminator value '{value}' for '{entityType}' is not a string. Configure a string discriminator value instead. What it means
In a non-TPH hierarchy (TPT or TPC), EF Core uses the entity 'short name' as an implicit discriminator value, and these implicit discriminator values must be strings. A configured discriminator value that is not a string was found on a derived type. Thrown from ValidateInheritanceMapping while iterating derived types in a non-TPH hierarchy.
Source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:2151
var derivedTypes = entityType.GetDerivedTypesInclusive().ToList();
var discriminatorValues = new Dictionary<string, IEntityType>();
foreach (var derivedType in derivedTypes)
{
foreach (var complexProperty in derivedType.GetDeclaredComplexProperties())
{
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>View on GitHub (pinned to dbf9771522)
Solutions
- Change HasValue(...) to supply a string discriminator value (e.g. HasValue("Student")).
- Remove the custom discriminator value and let EF use the entity short name (a string by default).
- If a non-string discriminator is required, use TPH instead of TPT/TPC.
Example fix
// before (TPT hierarchy)
modelBuilder.Entity<Person>()
.UseTptMappingStrategy()
.HasDiscriminator(p => p.Kind)
.HasValue<Student>(1)
.HasValue<Teacher>(2);
// after (string discriminator values in TPT/TPC)
modelBuilder.Entity<Person>()
.UseTptMappingStrategy()
.HasDiscriminator(p => p.Kind)
.HasValue<Student>("Student")
.HasValue<Teacher>("Teacher"); Defensive patterns
Strategy: validation
Validate before calling
using (var ctx = new MyContext()) { ctx.Model.ToDebugString(); }
// Assert all discriminator values in non-TPH hierarchies are strings.
foreach (var root in ctx.Model.GetEntityTypes().Where(e => e.BaseType == null))
{
var s = (string?)root[Microsoft.EntityFrameworkCore.Metadata.RelationalAnnotationNames.MappingStrategy];
if (s is null or "TPH") continue;
foreach (var d in root.GetDerivedTypesInclusive())
{
var v = d.GetDiscriminatorValue();
if (v is not null and not string)
Debug.Fail($"Discriminator value {v} ({v!.GetType().Name}) on {d.Name} is not a string under {s}.");
}
} Try / catch
try { using var ctx = new MyContext(); _ = ctx.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("is not a string. Configure a string discriminator value"))
{ log.Error("Non-string discriminator in TPT/TPC; use a string value or switch to TPH: {Msg}", ex.Message); throw; } Prevention
- In TPT/TPC hierarchies, pass string discriminator values to HasValue(...) or omit them to use entity short names.
- When migrating from TPH, sweep and convert any int/enum discriminator values.
- Cover discriminator-value types in a startup model-build test.
When it happens
Trigger: Calling HasDiscriminator(...).HasValue(42) (int) or .HasValue(MyEnum.A) on a derived entity in a hierarchy configured with UseTptMappingStrategy() or UseTpcMappingStrategy(); using an enum or numeric discriminator value in TPT/TPC.
Common situations: Carrying over an int/enum discriminator configuration when migrating from TPH to TPT/TPC; using value-typed discriminators by habit in a TPC hierarchy; mixing TPH-style discriminator values into a non-TPH hierarchy.
Related errors
- The mapping strategy '{mappingStrategy}' specified on '{enti
- The derived entity type '{entityType}' was configured with t
- The short name for '{entityType1}' is '{discriminatorValue}'
- The mapping strategy '{mappingStrategy}' used for '{entityTy
- Both '{entityType}' and '{otherEntityType}' are mapped to th
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/bfa9571fef3e52ba.
Report an issue: GitHub.