diff --git a/Control/Applicative/Backwards.hs b/Control/Applicative/Backwards.hs
--- a/Control/Applicative/Backwards.hs
+++ b/Control/Applicative/Backwards.hs
@@ -27,6 +27,9 @@
   ) where
 
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 
 import Prelude hiding (foldr, foldr1, foldl, foldl1, null, length)
 import Control.Applicative
@@ -100,3 +103,10 @@
     {-# INLINE traverse #-}
     sequenceA (Backwards t) = fmap Backwards (sequenceA t)
     {-# INLINE sequenceA #-}
+
+#if MIN_VERSION_base(4,12,0)
+-- | Derived instance.
+instance Contravariant f => Contravariant (Backwards f) where
+    contramap f = Backwards . contramap f . forwards
+    {-# INLINE contramap #-}
+#endif
diff --git a/Control/Monad/Trans/Error.hs b/Control/Monad/Trans/Error.hs
--- a/Control/Monad/Trans/Error.hs
+++ b/Control/Monad/Trans/Error.hs
@@ -58,6 +58,9 @@
 import Control.Monad.Signatures
 import Control.Monad.Trans.Class
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 
 import Control.Applicative
 import Control.Exception (IOException)
@@ -262,6 +265,11 @@
 
 instance (Error e, MonadIO m) => MonadIO (ErrorT e m) where
     liftIO = lift . liftIO
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (ErrorT e m) where
+    contramap f = ErrorT . contramap (fmap f) . runErrorT
+#endif
 
 -- | Signal an error value @e@.
 --
diff --git a/Control/Monad/Trans/Except.hs b/Control/Monad/Trans/Except.hs
--- a/Control/Monad/Trans/Except.hs
+++ b/Control/Monad/Trans/Except.hs
@@ -51,6 +51,9 @@
 import Control.Monad.Signatures
 import Control.Monad.Trans.Class
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Functor.Identity
 
 import Control.Applicative
@@ -253,6 +256,12 @@
 instance (MonadZip m) => MonadZip (ExceptT e m) where
     mzipWith f (ExceptT a) (ExceptT b) = ExceptT $ mzipWith (liftA2 f) a b
     {-# INLINE mzipWith #-}
+#endif
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (ExceptT e m) where
+    contramap f = ExceptT . contramap (fmap f) . runExceptT
+    {-# INLINE contramap #-}
 #endif
 
 -- | Signal an exception value @e@.
diff --git a/Control/Monad/Trans/Identity.hs b/Control/Monad/Trans/Identity.hs
--- a/Control/Monad/Trans/Identity.hs
+++ b/Control/Monad/Trans/Identity.hs
@@ -36,6 +36,9 @@
 import Control.Monad.Signatures
 import Control.Monad.Trans.Class (MonadTrans(lift))
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 
 import Control.Applicative
 import Control.Monad (MonadPlus(mzero, mplus))
@@ -153,6 +156,12 @@
 instance MonadTrans IdentityT where
     lift = IdentityT
     {-# INLINE lift #-}
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant f => Contravariant (IdentityT f) where
+    contramap f = IdentityT . contramap f . runIdentityT
+    {-# INLINE contramap #-}
+#endif
 
 -- | Lift a unary operation to the new monad.
 mapIdentityT :: (m a -> n b) -> IdentityT m a -> IdentityT n b
diff --git a/Control/Monad/Trans/List.hs b/Control/Monad/Trans/List.hs
--- a/Control/Monad/Trans/List.hs
+++ b/Control/Monad/Trans/List.hs
@@ -34,6 +34,9 @@
 import Control.Monad.Signatures
 import Control.Monad.Trans.Class
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 
 import Control.Applicative
 import Control.Monad
@@ -151,6 +154,12 @@
 instance (MonadZip m) => MonadZip (ListT m) where
     mzipWith f (ListT a) (ListT b) = ListT $ mzipWith (zipWith f) a b
     {-# INLINE mzipWith #-}
+#endif
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (ListT m) where
+    contramap f = ListT . contramap (fmap f) . runListT
+    {-# INLINE contramap #-}
 #endif
 
 -- | Lift a @callCC@ operation to the new monad.
diff --git a/Control/Monad/Trans/Maybe.hs b/Control/Monad/Trans/Maybe.hs
--- a/Control/Monad/Trans/Maybe.hs
+++ b/Control/Monad/Trans/Maybe.hs
@@ -45,6 +45,9 @@
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.Except (ExceptT(..))
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 
 import Control.Applicative
 import Control.Monad (MonadPlus(mzero, mplus), liftM)
@@ -200,6 +203,12 @@
 instance (MonadZip m) => MonadZip (MaybeT m) where
     mzipWith f (MaybeT a) (MaybeT b) = MaybeT $ mzipWith (liftA2 f) a b
     {-# INLINE mzipWith #-}
+#endif
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (MaybeT m) where
+    contramap f = MaybeT . contramap (fmap f) . runMaybeT
+    {-# INLINE contramap #-}
 #endif
 
 -- | Lift a @callCC@ operation to the new monad.
diff --git a/Control/Monad/Trans/RWS/Lazy.hs b/Control/Monad/Trans/RWS/Lazy.hs
--- a/Control/Monad/Trans/RWS/Lazy.hs
+++ b/Control/Monad/Trans/RWS/Lazy.hs
@@ -63,6 +63,9 @@
 import Control.Monad.IO.Class
 import Control.Monad.Signatures
 import Control.Monad.Trans.Class
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Functor.Identity
 
 import Control.Applicative
@@ -230,6 +233,13 @@
 instance (Monoid w, MonadIO m) => MonadIO (RWST r w s m) where
     liftIO = lift . liftIO
     {-# INLINE liftIO #-}
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (RWST r w s m) where
+    contramap f m = RWST $ \r s ->
+      contramap (\ ~(a, s', w) -> (f a, s', w)) $ runRWST m r s
+    {-# INLINE contramap #-}
+#endif
 
 -- ---------------------------------------------------------------------------
 -- Reader operations
diff --git a/Control/Monad/Trans/RWS/Strict.hs b/Control/Monad/Trans/RWS/Strict.hs
--- a/Control/Monad/Trans/RWS/Strict.hs
+++ b/Control/Monad/Trans/RWS/Strict.hs
@@ -63,6 +63,9 @@
 import Control.Monad.IO.Class
 import Control.Monad.Signatures
 import Control.Monad.Trans.Class
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Functor.Identity
 
 import Control.Applicative
@@ -230,6 +233,13 @@
 instance (Monoid w, MonadIO m) => MonadIO (RWST r w s m) where
     liftIO = lift . liftIO
     {-# INLINE liftIO #-}
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (RWST r w s m) where
+    contramap f m = RWST $ \r s ->
+      contramap (\ (a, s', w) -> (f a, s', w)) $ runRWST m r s
+    {-# INLINE contramap #-}
+#endif
 
 -- ---------------------------------------------------------------------------
 -- Reader operations
diff --git a/Control/Monad/Trans/Reader.hs b/Control/Monad/Trans/Reader.hs
--- a/Control/Monad/Trans/Reader.hs
+++ b/Control/Monad/Trans/Reader.hs
@@ -49,6 +49,9 @@
 import Control.Monad.IO.Class
 import Control.Monad.Signatures
 import Control.Monad.Trans.Class
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Functor.Identity
 
 import Control.Applicative
@@ -205,6 +208,12 @@
     mzipWith f (ReaderT m) (ReaderT n) = ReaderT $ \ a ->
         mzipWith f (m a) (n a)
     {-# INLINE mzipWith #-}
+#endif
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (ReaderT r m) where
+    contramap f = ReaderT . fmap (contramap f) . runReaderT
+    {-# INLINE contramap #-}
 #endif
 
 liftReaderT :: m a -> ReaderT r m a
diff --git a/Control/Monad/Trans/State/Lazy.hs b/Control/Monad/Trans/State/Lazy.hs
--- a/Control/Monad/Trans/State/Lazy.hs
+++ b/Control/Monad/Trans/State/Lazy.hs
@@ -76,6 +76,9 @@
 import Control.Monad.IO.Class
 import Control.Monad.Signatures
 import Control.Monad.Trans.Class
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Functor.Identity
 
 import Control.Applicative
@@ -252,6 +255,13 @@
 instance (MonadIO m) => MonadIO (StateT s m) where
     liftIO = lift . liftIO
     {-# INLINE liftIO #-}
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (StateT s m) where
+    contramap f m = StateT $ \s ->
+      contramap (\ ~(a, s') -> (f a, s')) $ runStateT m s
+    {-# INLINE contramap #-}
+#endif
 
 -- | Fetch the current value of the state within the monad.
 get :: (Monad m) => StateT s m s
diff --git a/Control/Monad/Trans/State/Strict.hs b/Control/Monad/Trans/State/Strict.hs
--- a/Control/Monad/Trans/State/Strict.hs
+++ b/Control/Monad/Trans/State/Strict.hs
@@ -73,6 +73,9 @@
 import Control.Monad.IO.Class
 import Control.Monad.Signatures
 import Control.Monad.Trans.Class
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Functor.Identity
 
 import Control.Applicative
@@ -249,6 +252,13 @@
 instance (MonadIO m) => MonadIO (StateT s m) where
     liftIO = lift . liftIO
     {-# INLINE liftIO #-}
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (StateT s m) where
+    contramap f m = StateT $ \s ->
+      contramap (\ (a, s') -> (f a, s')) $ runStateT m s
+    {-# INLINE contramap #-}
+#endif
 
 -- | Fetch the current value of the state within the monad.
 get :: (Monad m) => StateT s m s
diff --git a/Control/Monad/Trans/Writer/Lazy.hs b/Control/Monad/Trans/Writer/Lazy.hs
--- a/Control/Monad/Trans/Writer/Lazy.hs
+++ b/Control/Monad/Trans/Writer/Lazy.hs
@@ -52,6 +52,9 @@
 import Control.Monad.IO.Class
 import Control.Monad.Trans.Class
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Functor.Identity
 
 import Control.Applicative
@@ -235,6 +238,12 @@
     mzipWith f (WriterT x) (WriterT y) = WriterT $
         mzipWith (\ ~(a, w) ~(b, w') -> (f a b, w `mappend` w')) x y
     {-# INLINE mzipWith #-}
+#endif
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (WriterT w m) where
+    contramap f = mapWriterT $ contramap $ \ ~(a, w) -> (f a, w)
+    {-# INLINE contramap #-}
 #endif
 
 -- | @'tell' w@ is an action that produces the output @w@.
diff --git a/Control/Monad/Trans/Writer/Strict.hs b/Control/Monad/Trans/Writer/Strict.hs
--- a/Control/Monad/Trans/Writer/Strict.hs
+++ b/Control/Monad/Trans/Writer/Strict.hs
@@ -55,6 +55,9 @@
 import Control.Monad.IO.Class
 import Control.Monad.Trans.Class
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Functor.Identity
 
 import Control.Applicative
@@ -238,6 +241,12 @@
     mzipWith f (WriterT x) (WriterT y) = WriterT $
         mzipWith (\ (a, w) (b, w') -> (f a b, w `mappend` w')) x y
     {-# INLINE mzipWith #-}
+#endif
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant m => Contravariant (WriterT w m) where
+    contramap f = mapWriterT $ contramap $ \ (a, w) -> (f a, w)
+    {-# INLINE contramap #-}
 #endif
 
 -- | @'tell' w@ is an action that produces the output @w@.
diff --git a/Data/Functor/Constant.hs b/Data/Functor/Constant.hs
--- a/Data/Functor/Constant.hs
+++ b/Data/Functor/Constant.hs
@@ -26,6 +26,9 @@
   ) where
 
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 
 import Control.Applicative
 import Data.Foldable
@@ -140,4 +143,10 @@
 instance Bitraversable Constant where
     bitraverse f _ (Constant a) = Constant <$> f a
     {-# INLINE bitraverse #-}
+#endif
+
+#if MIN_VERSION_base(4,12,0)
+instance Contravariant (Constant a) where
+    contramap _ (Constant a) = Constant a
+    {-# INLINE contramap #-}
 #endif
diff --git a/Data/Functor/Reverse.hs b/Data/Functor/Reverse.hs
--- a/Data/Functor/Reverse.hs
+++ b/Data/Functor/Reverse.hs
@@ -28,6 +28,9 @@
 
 import Control.Applicative.Backwards
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 
 import Prelude hiding (foldr, foldr1, foldl, foldl1, null, length)
 import Control.Applicative
@@ -129,3 +132,10 @@
     traverse f (Reverse t) =
         fmap Reverse . forwards $ traverse (Backwards . f) t
     {-# INLINE traverse #-}
+
+#if MIN_VERSION_base(4,12,0)
+-- | Derived instance.
+instance Contravariant f => Contravariant (Reverse f) where
+    contramap f = Reverse . contramap f . getReverse
+    {-# INLINE contramap #-}
+#endif
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,5 +1,8 @@
 -*-change-log-*-
 
+0.5.5.1 Ross Paterson <R.Paterson@city.ac.uk> Apr 2019
+	* Added Contravariant instances
+
 0.5.5.0 Ross Paterson <R.Paterson@city.ac.uk> Oct 2017
 	* Added mapSelect and mapSelectT
 	* Renamed selectToCont to selectToContT for consistency
diff --git a/legacy/pre711/Data/Functor/Compose.hs b/legacy/pre711/Data/Functor/Compose.hs
--- a/legacy/pre711/Data/Functor/Compose.hs
+++ b/legacy/pre711/Data/Functor/Compose.hs
@@ -35,6 +35,9 @@
   ) where
 
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 
 import Control.Applicative
 #if __GLASGOW_HASKELL__ >= 708
@@ -144,3 +147,8 @@
 instance (Alternative f, Applicative g) => Alternative (Compose f g) where
     empty = Compose empty
     Compose x <|> Compose y = Compose (x <|> y)
+
+#if MIN_VERSION_base(4,12,0)
+instance (Functor f, Contravariant g) => Contravariant (Compose f g) where
+    contramap f (Compose fga) = Compose (fmap (contramap f) fga)
+#endif
diff --git a/legacy/pre711/Data/Functor/Product.hs b/legacy/pre711/Data/Functor/Product.hs
--- a/legacy/pre711/Data/Functor/Product.hs
+++ b/legacy/pre711/Data/Functor/Product.hs
@@ -45,6 +45,9 @@
 #endif
 import Data.Foldable (Foldable(foldMap))
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Monoid (mappend)
 import Data.Traversable (Traversable(traverse))
 #if __GLASGOW_HASKELL__ >= 702
@@ -145,4 +148,9 @@
 #if MIN_VERSION_base(4,4,0)
 instance (MonadZip f, MonadZip g) => MonadZip (Product f g) where
     mzipWith f (Pair x1 y1) (Pair x2 y2) = Pair (mzipWith f x1 x2) (mzipWith f y1 y2)
+#endif
+
+#if MIN_VERSION_base(4,12,0)
+instance (Contravariant f, Contravariant g) => Contravariant (Product f g) where
+    contramap f (Pair a b) = Pair (contramap f a) (contramap f b)
 #endif
diff --git a/legacy/pre711/Data/Functor/Sum.hs b/legacy/pre711/Data/Functor/Sum.hs
--- a/legacy/pre711/Data/Functor/Sum.hs
+++ b/legacy/pre711/Data/Functor/Sum.hs
@@ -40,6 +40,9 @@
 #endif
 import Data.Foldable (Foldable(foldMap))
 import Data.Functor.Classes
+#if MIN_VERSION_base(4,12,0)
+import Data.Functor.Contravariant
+#endif
 import Data.Monoid (mappend)
 import Data.Traversable (Traversable(traverse))
 #if __GLASGOW_HASKELL__ >= 702
@@ -125,3 +128,9 @@
 instance (Traversable f, Traversable g) => Traversable (Sum f g) where
     traverse f (InL x) = InL <$> traverse f x
     traverse f (InR y) = InR <$> traverse f y
+
+#if MIN_VERSION_base(4,12,0)
+instance (Contravariant f, Contravariant g) => Contravariant (Sum f g) where
+    contramap f (InL xs) = InL (contramap f xs)
+    contramap f (InR ys) = InR (contramap f ys)
+#endif
diff --git a/transformers.cabal b/transformers.cabal
--- a/transformers.cabal
+++ b/transformers.cabal
@@ -1,5 +1,5 @@
 name:         transformers
-version:      0.5.5.0
+version:      0.5.5.1
 license:      BSD3
 license-file: LICENSE
 author:       Andy Gill, Ross Paterson
