* Elm has tagged union types, meaning that you can make a value that many have one of many types, and pattern match on its possible variants.
* Elm has type inference, Java does not. When you declare a variable in Java, you need to know what type it is. There's no such need in Elm.
* Elm has first-class functions, so variables can have type a -> b, and you can build arbitrarily complicated types using function types, put them in tuples, etc.
* Java has classes, subtyping, inheritance, etc. Elm doesn't have that, because subtyping gets in the way of inference, and because it's not nearly as necessary when you don't have mutable data.
There are many other differences between the languages, but they're not necessarily differences in the type system. For example, Java has mutable variables and Elm does not, but there are strongly typed functional languages, like ML, which have mutable variables.
As for the actual typechecking algorithms, Elm uses something like
Algorithm W, but a more advanced, constraint-based version which helps with speed and can actually accept a few more programs.
Typechecking is based on unification.
I can't speak too much about Java, but I imagine they're using something like abstract interpretation to typecheck.