Constrain input values
Maybe not all the differences, but most important in my opinion : 


enum vs text/varchar + check constraint.  


enum values are internally stored as integer numbers, so different storage requirements
ordering : order of enum values corresponds order in which values were entering during creation type, so for enum ('small', 'big') small &lt; big;  for text column  'big'&lt;'small'

enum vs foreign key 


performance-wise they should behave very similar, but you can bypass foreign key constraint by, for instance, disabling all triggers or changing session replication role
there is a bigger difference from data model perspective. If something has attributes, needs to be tracked, likely to be modified in either way, it should be stored as a separate entity in its own table. If it's just an attribute , e.g. color in many cases, then it's fine to store it as a enumerated type. 



Triggers are just not the right tool to implement check constraints. They add complexity, hide logic, add maintenance overhead.  In some cases they are "necessary evil" , but they definitely shouldn't be used just to do what check constraint can do.