overview
ℹ️ Important
Availability: .NET 7
- Documentation: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism?pivots=dotnet-7-0
 
System.Text.Json supports polymorphic type hierarchies with these attributes:
[JsonDerivedType]— indicates that the specified subtype should be opted into polymorphic serialization[JsonPolymorphic]— indicates that the type should be serialized polymorphically
serializing properties of a derived class
Consider this base class…
[JsonDerivedType(typeof(WeatherForecastWithCity))]
public class WeatherForecastBase
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}
…and this derived class:
public class WeatherForecastWithCity : WeatherForecastBase
{
    public string? City { get; set; }
}
Assume the type argument of Serialize<T> at compile time is WeatherForecastBase:
options = new JsonSerializerOptions
{
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize<WeatherForecastBase>(weatherForecastBase, options);
The City property is serialized because the weatherForecastBase object is actually a WeatherForecastWithCity object since we used the [JsonDerivedType] attribute:
{
  "City": "Milwaukee",
  "Date": "2022-09-26T00:00:00-05:00",
  "TemperatureCelsius": 15,
  "Summary": "Cool"
}
deserializing properties of a derived class
To enable polymorphic deserialization, a type discriminator must be specified for the derived class:
[JsonDerivedType(typeof(WeatherForecastBase), typeDiscriminator: "base")]
[JsonDerivedType(typeof(WeatherForecastWithCity), typeDiscriminator: "withCity")]
public class WeatherForecastBase
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}
public class WeatherForecastWithCity : WeatherForecastBase
{
    public string? City { get; set; }
}
This added metadata allows the serializer to serialize and deserialize the payload as WeatherForecastWithCity from its base WeatherForecastBase type:
WeatherForecastBase weather = new WeatherForecastWithCity
{
    City = "Milwaukee",
    Date = new DateTimeOffset(2022, 9, 26, 0, 0, 0, TimeSpan.FromHours(-5)),
    TemperatureCelsius = 15,
    Summary = "Cool"
}
var json = JsonSerializer.Serialize<WeatherForecastBase>(weather, options);
Console.WriteLine(json);
Output:
{
  "$type" : "withCity", // this is the type discriminator metadata 
  "City": "Milwaukee",
  "Date": "2022-09-26T00:00:00-05:00",
  "TemperatureCelsius": 15,
  "Summary": "Cool"
}
jsonpolymorphic
The [JsonPolymorphic] attribute customizes the type discriminator’s name. The default name is $type:
[JsonPolymorphic(TypeDiscriminatorPropertyName = "$discriminator")]
[JsonDerivedType(typeof(ThreeDimensionalPoint), typeDiscriminator: "3d")]
public class BasePoint
{
    public int X { get; set; }
    public int Y { get; set; }
}
public sealed class ThreeDimensionalPoint : BasePoint
{
    public int Z { get; set; }
}
BasePoint point = new ThreeDimensionalPoint { X = 1, Y = 2, Z = 3 };
var json = JsonSerializer.Serialize<BasePoint>(point);
Console.WriteLine(json);
// Sample output:
//  { "$discriminator": "3d", "X": 1, "Y": 2, "Z": 3 }