When running a test that's deserializing a JSON string, I get the error message:

Cannot deserialize JSON as abstract type: TestController.Item

The JSON contains a list of objects which is abstract and it's not possible to deserialize it.

public class TestController {
    private abstract class Item{
        public String bla;
        public String bla2;

    public class SomeItem extends Item{
        private SomeItem() {
            bla = 'bla';

    public class SomeClass{

        @Testvisible private List<Item> items;

        public Graph(List<SomeItem> someItems) {
            items = new List<Item>();
            items.addAll((List<Item>) someItems);

This is the test class:

public class TestController_Test {
    private static void testSomething() {
        TestController.SomeClass someClass = (TestController.SomeClass) System.JSON.deserialize(json, TestController.SomeClass.class);

        for(TestController.Item item : someClass.items) {


I found a github pull request with the same error. There is a Critical Update and I'm sure that this causes the problem.

Do you have any idea how to solve that problem?

  • 1
    Could you post the json string value?
    – arut
    Commented Aug 19, 2020 at 13:14
  • 1
    What is the purpose of private abstract class? Commented Aug 19, 2020 at 13:15

2 Answers 2


Even when this code would compile and run, it had a problem; you couldn't actually instantiate a SomeItem inside the list of Item, because the JSON parser wouldn't know what subtype you actually mean to use.

As such, the Critical Update is actually a good thing, because it fixes aberrant behavior with this type of code. The solution is to manually create the objects in memory.

This also points to a possible design flaw, if this is meant to be used with some sort of API that would use JSON. It simply won't work, because the system cannot determine the correct type of subclass to use for the data type, and in a strongly typed language like Apex, that's problematic.

Since everything is marked TestVisible, the correct solution would be to manually create the objects:

TestController.SomeClass wrapper = new TestController.SomeClass();
wrapper.items = new TestController.SomeItem[0];
wrapper.items.add(new TestController.SomeItem());
// etc //

In summary, there is no direct workaround. You must be able to deserialize into a concrete class. If you can't, then your options are something like constructing manually (above), using JSONGenerator, or using a generic Object (e.g. List<Map<String, Object>>).


I ran into this issue today due to the critical update activating. I was able to resolve it by changing my abstract class to a virtual class.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .