Dynamic Dispatch replacement for Generic methods
Personally, I would be able to live with your huge if statement if it remains straightforward, is well tested, and hidden in a nice class. I think a parser will often have these types of structures, especially if you are generating it from a grammar using a tool (like ANTLR for example) instead of coding it by hand.

You could slightly improve the huge if statement by factoring out currentNode.getData().getClass() (instead of currentNode.getData()):

final Class&lt;?&gt; dataClass = currentNode.getData().getClass();
if (Number.class.isAssignableFrom(dataClass))
    dxNode = new TreeNode&lt;Double&gt;(0.0);
else if (AddOperator.class.isAssignableFrom(dataClass))
    dxNode = deriveAddContext((Node&lt;AddOperator&gt;) currentNode);
else if (MulOperator.class.isAssignableFrom(dataClass))
    dxNode = deriveMulContext((Node&lt;MulOperator&gt;) currentNode);
else if (SineFunction.class.isAssignableFrom(dataClass))
    dxNode = deriveSineContext((Node&lt;SineFunction&gt;) currentNode);


You could also consider using Java 8 to create an explicit mapping between the class the current node (data) is assignable from and the initialization code for dxNode using lambda expressions. This has the advantage that you should be able to extend the expression types by adding a single line to the map:

public Node deriveAlternative(final Node currentNode, final Node parentNode) {
    Node dxNode = null;

    final Map&lt;Class&lt;?&gt;, Function&lt;Node, Node&gt;&gt; deriveMap = new HashMap&lt;&gt;();
    deriveMap.put(Number.class, n -&gt; new TreeNode&lt;Double&gt;(0.0));
    deriveMap.put(AddOperator.class, n -&gt; deriveAddContext((Node&lt;AddOperator&gt;) n));
    deriveMap.put(MulOperator.class, n -&gt; deriveMulContext((Node&lt;MulOperator&gt;) n));
    deriveMap.put(SineFunction.class, n -&gt; deriveSineContext((Node&lt;SineFunction&gt;) n));

    final Optional&lt;Class&lt;?&gt;&gt; optionalKey = deriveMap.keySet().stream()
            .filter(key -&gt; key.isAssignableFrom(currentNode.getData().getClass()))
            .findFirst();

    if (optionalKey.isPresent()) {
        final Class&lt;?&gt; key = optionalKey.get();
        dxNode = deriveMap.get(key).apply(currentNode);
    }

    if (dxNode != null &amp;&amp; parentNode != null)
        dxNode.setParent(parentNode);

    return dxNode;
}