The types represent different levels of abstraction. TypeElement represent the class, declared in the code, while TypeMirror represents that class' specific usage.
For example:
class Foo {
public void hello() {
}
}
class Bar {
public void hello(Foo foo) {
}
}
In this example there will be 2 instances of TypeElement - for each one of the declared classes. Also there will be 2 instances of ExecutableElement, representing each one of the methods (A.hello and B.hello).
If you will take a look at the ExecutableElement of B.hello(), there will be information about method parameters and their types, while in this case, the types will be represented with TypeMirror. From TypeMirror you always can get corresponding TypeElement.
TypeElement - represents class declaration and contains all the information about the declaration itself
TypeMirror - represents the occurance (the specific usage) of the class in the code and has all the information, which is specific to that occurance. From the occurance you always can get the declaration, but not vice versa.
Despite, both entities (TypeElement and TypeMirror) might look representing the same entities at the first glance, but that's not true. Each one of them has some information, which is available only on that specific level of abstraction.
For example: annotations of the declared class or method - are available in corresponding TypeElement/ExecutableElement, but not in TypeMirror.
Another important aspect of difference is generics:
class Foo<T> {
public void hello() {
}
}
class Bar {
public void hello(Foo<String> foo) {
}
}
In this example, the TypeElement of Foo will have information about type parameters, their constraints, bounds, etc.
But TypeMirror of the B.hello's first parameter will have specific type argument (String), which was used in this specific occurance of using of Foo class