It might surprise you but the exact same thing would happen if you had generated the same code using javac using the same class loader setup. What you observe is implied by how package-privacy is specified in the JLS. Your non-interface class

public abstract class Algorithm { abstract int execute(); }

defines a package-private method. Since you do not define a custom name for the generated class, Byte Buddy generates a subclass with a random name that lives in the same package. Byte Buddy does further discover the executable method as overridable from the generated subclass and implements it exactly as you would expect it to.

However, you are using the ClassLoadingStrategy.Default.WRAPPER strategy to load the class which creates a new child-class loader of the one loading Algorithm . In Java, at runtime, two packages are however only equal if the name of the package is equal and both packages are loaded by the same ClassLoader . The later condition is not true for your case such that the JVM does no longer apply polymorphism to the execute class. By calling

((Algorithm) type.newInstance()).execute();

you are therefore not invoking the generated method but the original, abstract method. Therefore - in accordance to the JLS - an AbstractMethodError is thrown.

To fix this problem, you either need to load the generated class in the same package, using the default INJECTION strategy or you have to define execute as a public (this is implicit when defining an interface) or protected method such that the rules for polymorphism that you expect do apply. As a third option, you could invoke the correct runtime method by