Restricting types not related through inheritance without using instanceOf by creating own class hierarchy Restricting types not related through inheritance without using instanceOf by creating own class hierarchy. It needs to interact with a key value data store, will convert to object before putting, but needs to convert back to fields after getting from DB with Function&lt;Object,Field&gt;. Something about this with regards to inheritance doesn't seem right, although it works.

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;

/**
 * Field, placeholder for a type that can be stored in db
 */
@EqualsAndHashCode
public class Field&lt;T&gt; {
    @Getter
    private T featureValue;

    Field(@NonNull T value) {
        this.featureValue = value;
    }

    public static class Factory {
    }
}
//convert object to feature value (since ddb returns Map&lt;String, Object&gt; on Item.asMap)
//convert particular type of object to feature value (say Integer, String)
//abstract Field from(T value);
//convert feature value to particular type, call from drvd (from base =&gt; obj)
//enum or getEnum for some type expressed as string factory

/**
 * Field for a boolean type
 */
public class BooleanField extends Field&lt;Boolean&gt; {
    public BooleanField(Boolean value) {
        super(value);
    }

    public static BooleanField fromObject(Object value) {
        return new BooleanField((Boolean) value);
    }
}

import java.util.List;

/**
 * Field for a list data type, holds a list of Field
 */
public class ListField extends Field&lt;List&lt;Field&gt;&gt; {
    public ListField(List&lt;Field&gt; value) {
        super(value);
    }

    public static ListField fromObject(Object value) {
        return new ListField((List&lt;Field&gt;) value);
    }
}


import java.util.Map;

/**
 * Field for a map type, holds a map of String to Field
 */
public class MapField extends Field&lt;Map&lt;String, Field&gt;&gt; {
    public MapField(Map&lt;String, Field&gt; value) {
        super(value);
    }

    public static MapField fromObject(Object value) {
        return new MapField((Map&lt;String, Field&gt;) value);
    }
}


/**
 * Field for a Numeric type
 */
public class NumericField extends Field&lt;Number&gt; {
    public NumericField(Number value) {
        super(value);
    }

    public static NumericField fromObject(Object value) {
        return new NumericField((Number) value);
    }
}


import java.util.Set;

/**
 * Field for a set data type
 */
public class SetField extends Field&lt;Set&lt;Field&gt;&gt; {
    public SetField(Set&lt;Field&gt; value) {
        super(value);
    }

    public static SetField fromObject(Object value) {
        return new SetField((Set&lt;Field&gt;) value);
    }
}


/**
 * Field for a string type
 */
public class StringField extends Field&lt;String&gt; {
    public StringField(String value) {
        super(value);
    }

    public static StringField fromObject(Object value) {
        return new StringField((String) value);
    }
}
You can create the same thing by not creating all those subclasses. I also see that you can't use the instanceOf method. My first intention was getting this test method to work:

System.out.println(Field.fromObject(new ArrayList()).getFeatureValue().getClass());
System.out.println(Field.fromObject(new Integer(6)).getFeatureValue());
System.out.println(Field.fromObject(new Integer(6)).getFeatureValue().getClass());
System.out.println(Field.fromObject(Boolean.TRUE)); // null or error


As you can see, I call Field and not an implementation of the Field class. But I also want the correct class back as what class I put in there, so the output should be:

class java.util.ArrayList
6
class java.lang.Integer
null


In order that Boolean is a type what can't be created. After searching on this topic you come always back to instanceOf or what you did. The thing what I wanted is something I can refactor really easy, so it needed to be on 1 place to refactor.

Enum could help me with that, but still having trouble with subclasses what also need to be valid. (ArrayList if List is allowed)

I refactored your code to this. If you need to create the subclasses, you could still look at the static method.

public class Field&lt;T&gt; {

    private T featureValue;

    Field(T value) {
        this.featureValue = value;
    }

    public T getFeatureValue() {
        return featureValue;
    }

    public static &lt;T&gt; Field&lt;T&gt; fromObject(T value) {
        for (Allowed allow : Allowed.values()) {
            if (allow.getClazz().isAssignableFrom(value.getClass())) {
                return new Field&lt;&gt;(value);
            }
        }
        return null;
    }

    private enum Allowed {

        INTEGER(Integer.class),
        STRING(String.class),
        LIST(List.class);

        private final Class clazz;

        private Allowed(Class clazz) {
            this.clazz = clazz;
        }

        public Class getClazz() {
            return clazz;
        }
    }
}


As you can see, we iterate the Enum values to check the restrictions. With this solution you can add also the following test:

List&lt;String&gt; list  = Field.fromObject(new ArrayList&lt;String&gt;()).getFeatureValue();


As you can see, no casting is required.

The next is broken code:

List&lt;String&gt; list  = Field.fromObject(new ArrayList&lt;Boolean&gt;()).getFeatureValue();


which is also good because these are 2 different types.