Deserializing response to correct type I use this method to get either Customer or Account. The server will determine which type it is.

The response will have a property "Type": "Customer" or "Type": "Account".

I first deserialize to Client (supertype) to check the Type property. Then deserialize to either Customer or Account.

public async Task&lt;Models.Entities.Client&gt; GetClient(int clientId)
{
    var getClientRequest = new RestRequest("client/details", Method.GET);
    getClientRequest.AddQueryParameter("ClientId", clientId);

    var jsonResponse = await _requestService.DoRequest(getClientRequest);

    var client = JsonConvert.DeserializeObject&lt;Models.Entities.Client&gt;(jsonResponse);

    switch (client.Type)
    {
        case ClientKind.Account:
            var account = JsonConvert.DeserializeObject&lt;Account&gt;(jsonResponse)
            return account;
        default:
            var customer = JsonConvert.DeserializeObject&lt;Customer&gt;(jsonResponse);
            return customer;
    }
}


Example responses:

{
    "ClientId": 1,
    "Type": "Account",
    "Name": "Company Inc."
}


{
    "ClientId": 2,
    "Type": "Customer",
    "Name":
    {
        "First": "John",
        "Last": "Smith"
    },
    "DateOfBirth": "1960-12-01"
}


DTOs:

public class Client
{
    public int ClientId { get; set; }
    public ClientType Type { get; set; }
}

public class Account : Client
{
    public string Name { get; set; }
}

public class Customer : Client
{
    public PersonalName Name { get; set; }
    public DateTime DateOfBirth { get; set; }
}
Your code could be rewritten:

var settings = new JsonSerializerSettings { 
     TypeNameHandling = TypeNameHandling.All,
     SerializationBinder = knownTypesBinder // &lt;- see security risk below
};
var client = JsonConvert.DeserializeObject&lt;Models.Entities.Client&gt;(jsonResponse);
return client; // &lt;- strongly-typed



Make sure both server and client use the settings
If you have declared  public ClientType Type { get; set; } just to enable two-phase serialisation (base entity - concrete entity), you should remove it from the code.
The two-phase serialisation hack can be replaced with a strongly-typed serialisation using TypeNameHandling = TypeNameHandling.All. Example




As suggested in the comments, we need to address the security aspect also. Hence, knownTypesBinder is used to mitigate a security risk.

// based on https://www.newtonsoft.com/json/help/html/SerializeSerializationBinder.htm
var knownTypesBinder = new KnownTypesBinder
{
    KnownTypes = new List&lt;Type&gt; { typeof(Customer), typeof(Account) }
};

public class KnownTypesBinder : ISerializationBinder
{
    public IList&lt;Type&gt; KnownTypes { get; set; }

    public Type BindToType(string assemblyName, string typeName)
    {
        return KnownTypes.SingleOrDefault(t =&gt; t.Name == typeName);
    }

    public void BindToName(Type serializedType, out string assemblyName, 
        out string typeName)
    {
        assemblyName = null;
        typeName = serializedType.Name;
    }
}