Covariant and contravariant types are concepts that relate to how subtyping affects generic types in Java. Covariant types mean that if A is a subtype of B, then C<A> is a subtype of C<B>, where C is a generic type. For example, List<String> is a subtype of List<Object>, because String is a subtype of Object. Contravariant types mean that if A is a subtype of B, then C<B> is a subtype of C<A>, where C is a generic type. For example, Comparator<Object> is a subtype of Comparator<String>, because Object is a supertype of String. A common pitfall is to misuse covariant and contravariant types, and cause compile-time or runtime errors. To avoid this pitfall, you should follow the rules of generics and subtyping, such as using bounded wildcards, avoiding raw types, and respecting the PECS principle (Producer Extends, Consumer Super).