using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
var settings = new JsonSerializerSettings
ContractResolver = new DefaultContractResolver
NamingStrategy = new SnakeCaseNamingStrategy()
var serialized = JsonConvert.SerializeObject(
SomeProperty = new PropertyImplementationA
PropertyA = "some string value"
Console.WriteLine("Serialized correctly:");
Console.WriteLine(serialized);
var deserialized = JsonConvert.DeserializeObject<Container>(serialized);
Console.WriteLine("Converter not used when deserializing");
Console.WriteLine(JsonConvert.SerializeObject(deserialized, settings));
class PropertyImplementationA : PropertyBase
override public string Type => nameof(PropertyImplementationA);
public string PropertyA { get; set; }
class PropertyImplementationB : PropertyBase
override public string Type => nameof(PropertyImplementationB);
public int PropertyB { get; set; }
abstract class PropertyBase
public abstract string Type { get; }
class PropertyConverter : JsonConverter<PropertyBase>
override public void WriteJson(JsonWriter writer, PropertyBase? value, JsonSerializer serializer)
throw new NotImplementedException();
override public bool CanWrite => false;
override public PropertyBase? ReadJson(JsonReader reader, Type objectType, PropertyBase? existingValue, bool hasExistingValue, JsonSerializer serializer)
Console.WriteLine("JsonConverter used");
if (reader.TokenType == JsonToken.Null) return null;
var jObject = JObject.Load(reader);
var target = Create(jObject);
if (target != null) serializer.Populate(jObject.CreateReader(), target);
private PropertyBase Create(JObject jObject)
throw new ArgumentNullException(nameof(jObject));
var sourceType = jObject.SelectToken("type")?.Value<string>();
nameof(PropertyImplementationA) => new PropertyImplementationA(),
nameof(PropertyImplementationB) => new PropertyImplementationB(),
[JsonConverter(typeof(PropertyConverter))]
public PropertyBase SomeProperty { get; set; }