Curiously Recurring Template Pattern (CRTP) implementation
As far I can tell this doesn't generate any warnings:

class IntValue implements Value&lt;IntValue&gt; {

    Integer value;

    public IntValue(Integer value) {
        this.value = value;
    }

    public Integer getValue() {
        return value;
    }

    @Override
    public IntValue deepCopy() {
        return new IntValue(value);
    }
}


class ArrayValue&lt;T extends Value&lt;T&gt;&gt; implements Value&lt;ArrayValue&lt;T&gt;&gt; {

    List&lt;T&gt; values;

    public ArrayValue() {
        this(new ArrayList&lt;&gt;());
    }

    public ArrayValue(List&lt;T&gt; values) {
        this.values = values;
    }

    @Override
    public ArrayValue&lt;T&gt; deepCopy() {
        List&lt;T&gt; copyValues = new ArrayList&lt;&gt;();
        values.forEach(value -&gt; copyValues.add(value.deepCopy()));
        return new ArrayValue&lt;&gt;(copyValues);
    }
}


But it makes more sense to do it without CRTP:

public interface Value&lt;T&gt; {
    Value&lt;T&gt; deepCopy();
    T getValue();
}


class IntValue implements Value&lt;Integer&gt; {

    Integer value;

    public IntValue(Integer value) {
        this.value = value;
    }

    @Override
    public Integer getValue() {
        return value;
    }

    @Override
    public IntValue deepCopy() {
        return new IntValue(value);
    }
}


class ArrayValue&lt;T&gt; implements Value&lt;List&lt;Value&lt;T&gt;&gt;&gt; {

    List&lt;Value&lt;T&gt;&gt; values;

    public ArrayValue() {
        this(new ArrayList&lt;&gt;());
    }

    public ArrayValue(List&lt;Value&lt;T&gt;&gt; values) {
        this.values = values;
    }

    @Override
    public ArrayValue&lt;T&gt; deepCopy() {
        List&lt;Value&lt;T&gt;&gt; copyValues = new ArrayList&lt;&gt;();
        values.forEach(value -&gt; copyValues.add(value.deepCopy()));
        return new ArrayValue&lt;&gt;(copyValues);
    }

    @Override
    public List&lt;Value&lt;T&gt;&gt; getValue() {
        return values;
    }
}

class X {

    public static Value sub(Value&lt;Integer&gt; a, Value&lt;Integer&gt; b) {
         return new IntValue(b.getValue() - b.getValue());
    }
}