As far as I'm concerned, the minimal is sum, products and, most importantly, abstract parametric datatypes. This is sufficient for phantom types, and then the fun starts. More complex parametric types (with ad-hoc polymorphism for example) then extends what you can do.