The way the problem is decomposed doesn't feel right. In particular, there are too many interfaces, and `Additive`, `Divisible`, `Negative` are unnecessarily disconnected. I recommend to follow a more (mathematically) natural path. The Gram-Schmidt process works in any inner product space (which is by definition a vector space equipped with an inner product), so consider an abstract class InnerProductSpace <V, F> { AbelianGroup<V> vectors; Field<F> scalars; V scale(V vector, F scalar); F innerProduct(V v1, V v2); V[] orthogonalize(V[] basis) { // your Gram-Schmidt implementation here } } As a side note, I wouldn't call an orthogonalization method `GramShmidt`. As a client of this library I am not concerned with which process is used. The only thing I care about is that there is the method taking a basis and returning an orthogonalized one. I also took a liberty to make a shortcut and not spell out the VectorSpace interface, to which a `scale` method really belongs. The `Field` is what holds addition and multiplication together: public interface Field<F> { F add(F f1, F f2); F mul(F f1, F f2); F neg(F f); F inv(F f); } It is OK to have `sub` and `div` instead of `neg` and `inv`. Notice that the field _must_ be closed under its operation. An addition (or multiplication) returning a type different than the type of arguments makes no mathematical sense. I have to admit that I have no idea how to express other constraints a.k.a. field axioms. I doubt that it is possible.