diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -4,6 +4,10 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/).
 
+## [0.4.13] - 2018-07-18
+### Added
+- Laws for `Enum` typeclass.
+
 ## [0.4.12] - 2018-06-07
 ### Added
 - Remaining laws for `Storable` typeclass.
diff --git a/quickcheck-classes.cabal b/quickcheck-classes.cabal
--- a/quickcheck-classes.cabal
+++ b/quickcheck-classes.cabal
@@ -1,5 +1,5 @@
 name: quickcheck-classes
-version: 0.4.12
+version: 0.4.13
 synopsis: QuickCheck common typeclasses
 description:
   This library provides QuickCheck properties to ensure
@@ -11,7 +11,7 @@
 homepage: https://github.com/andrewthad/quickcheck-classes#readme
 license: BSD3
 license-file: LICENSE
-author: Andrew Martin
+author: Andrew Martin, Daniel Cartwright
 maintainer: andrew.thaddeus@gmail.com
 copyright: 2018 Andrew Martin
 category: Testing
@@ -53,16 +53,21 @@
     Test.QuickCheck.Classes.Alt
     Test.QuickCheck.Classes.Alternative
     Test.QuickCheck.Classes.Applicative
+    Test.QuickCheck.Classes.Apply
+    -- Test.QuickCheck.Classes.Arrow
     Test.QuickCheck.Classes.Bifunctor
     Test.QuickCheck.Classes.Bits
+    Test.QuickCheck.Classes.Category
     Test.QuickCheck.Classes.Common
     Test.QuickCheck.Classes.Compat
+    Test.QuickCheck.Classes.Enum
     Test.QuickCheck.Classes.Eq
     Test.QuickCheck.Classes.Foldable
     Test.QuickCheck.Classes.Functor
     Test.QuickCheck.Classes.Integral
     Test.QuickCheck.Classes.Json
     Test.QuickCheck.Classes.Monad
+    Test.QuickCheck.Classes.MonadFail
     Test.QuickCheck.Classes.MonadPlus
     Test.QuickCheck.Classes.MonadZip
     Test.QuickCheck.Classes.Monoid
@@ -98,8 +103,10 @@
       base
     , quickcheck-classes
     , QuickCheck
+    , containers 
     , primitive
     , vector
+    , semigroupoids 
     , transformers
     , tagged
   if flag(aeson)
diff --git a/src/Test/QuickCheck/Classes.hs b/src/Test/QuickCheck/Classes.hs
--- a/src/Test/QuickCheck/Classes.hs
+++ b/src/Test/QuickCheck/Classes.hs
@@ -27,6 +27,8 @@
 #endif
   , monoidLaws
   , ordLaws
+  , enumLaws
+  , boundedEnumLaws
   , primLaws
   , semigroupLaws
   , showReadLaws
@@ -36,6 +38,7 @@
   , alternativeLaws
 #if defined(VERSION_semigroupoids)
   , altLaws
+  , applyLaws
 #endif
   , applicativeLaws
 #if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
@@ -60,6 +63,7 @@
 
 -- Ground Types
 import Test.QuickCheck.Classes.Bits
+import Test.QuickCheck.Classes.Enum
 import Test.QuickCheck.Classes.Eq
 import Test.QuickCheck.Classes.Integral
 #if MIN_VERSION_base(4,7,0)
@@ -82,6 +86,7 @@
 import Test.QuickCheck.Classes.Alternative
 #if defined(VERSION_semigroupoids)
 import Test.QuickCheck.Classes.Alt
+import Test.QuickCheck.Classes.Apply
 #endif
 import Test.QuickCheck.Classes.Applicative
 #if MIN_VERSION_transformers(0,5,0)
diff --git a/src/Test/QuickCheck/Classes/Apply.hs b/src/Test/QuickCheck/Classes/Apply.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/QuickCheck/Classes/Apply.hs
@@ -0,0 +1,53 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+{-# OPTIONS_GHC -Wall #-}
+
+module Test.QuickCheck.Classes.Apply
+  (
+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
+#if defined(VERSION_semigroupoids)
+    applyLaws
+#endif
+#endif
+) where
+
+import Data.Functor
+
+#if defined(VERSION_semigroupoids)
+import qualified Data.Functor.Apply as FunctorApply
+#endif
+
+import Test.QuickCheck hiding ((.&.))
+#if MIN_VERSION_QuickCheck(2,10,0)
+import Test.QuickCheck.Arbitrary (Arbitrary1(..))
+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
+import Data.Functor.Classes
+#endif
+#endif
+import Test.QuickCheck.Property (Property)
+
+import Test.QuickCheck.Classes.Common
+
+#if MIN_VERSION_QuickCheck(2,10,0)
+
+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
+
+-- | Tests the following alt properties:
+--
+-- [/LiftF2 (1)/]
+--   @('FunctorApply.<.>') ≡ 'liftF2' 'id'@
+#if defined(VERSION_semigroupoids)
+applyLaws :: (FunctorApply.Apply f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
+applyLaws p = Laws "Apply"
+  [ ("LiftF2 part 1", applyLiftF2_1 p)
+  ]
+
+applyLiftF2_1 :: forall proxy f. (FunctorApply.Apply f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property
+applyLiftF2_1 _ = property $ \(Apply (f' :: f QuadraticEquation)) (Apply (x :: f Integer)) ->
+  let f = fmap runQuadraticEquation f'
+  in eq1 (FunctorApply.liftF2 id f x) (f FunctorApply.<.> x)
+#endif
+#endif
+#endif
+
diff --git a/src/Test/QuickCheck/Classes/Category.hs b/src/Test/QuickCheck/Classes/Category.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/QuickCheck/Classes/Category.hs
@@ -0,0 +1,73 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+{-# OPTIONS_GHC -Wall #-}
+
+module Test.QuickCheck.Classes.Category
+  (
+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
+    categoryLaws
+  , commutativeCategoryLaws
+#endif  
+  ) where
+
+import Prelude hiding (id, (.))
+import Control.Category (Category(..))
+import Test.QuickCheck hiding ((.&.))
+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
+import Data.Functor.Classes
+#endif
+import Test.QuickCheck.Property (Property)
+
+import Test.QuickCheck.Classes.Common
+
+#if MIN_VERSION_QuickCheck(2,10,0)
+
+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,5,0)
+
+-- | Tests the following 'Category' properties:
+--
+-- [/Right Identity/]
+--   @f '.' 'id' ≡ f
+-- [/Left Identity/]
+--   @'id' '.' f ≡ f@
+-- [/Associativity/]
+--   @f '.' (g '.' h) ≡ (f '.' g) '.' h@
+--
+-- /Note/: This property test is only available when this package is built with
+-- @base-4.9+@ or @transformers-0.5+@.
+categoryLaws :: (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Laws
+categoryLaws p = Laws "Category"
+  [ ("Right Identity", categoryRightIdentity p)
+  , ("Left Identity", categoryLeftIdentity p)
+  , ("Second Identity", categoryAssociativity p)
+  ]
+
+-- | Test everything from 'categoryLaws' plus the following:
+--
+-- [/Commutative/]
+--   @f '.' g ≡ g '.' f@
+--
+-- /Note/: This property test is only available when this package is built with
+-- @base-4.9+@ or @transformers-0.5+@.
+commutativeCategoryLaws :: (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Laws
+commutativeCategoryLaws p = Laws "Commutative Category" $ lawsProperties (categoryLaws p) ++
+  [ ("Commutative", categoryCommutativity p)
+  ]
+
+categoryRightIdentity :: forall proxy cat. (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Property
+categoryRightIdentity _ = property $ \(Apply2 (x :: cat Integer Integer)) -> eq2 (x . id) x
+
+categoryLeftIdentity :: forall proxy cat. (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Property
+categoryLeftIdentity _ = property $ \(Apply2 (x :: cat Integer Integer)) -> eq2 (id . x) x
+
+categoryAssociativity :: forall proxy cat. (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Property
+categoryAssociativity _ = property $ \(Apply2 (f :: cat Integer Integer)) (Apply2 (g :: cat Integer Integer)) (Apply2 (h :: cat Integer Integer)) -> eq2 (f . (g . h)) ((f . g) . h)
+
+categoryCommutativity :: forall proxy cat. (Category cat, Eq2 cat, Show2 cat, Arbitrary2 cat) => proxy cat -> Property
+categoryCommutativity _ = property $ \(Apply2 (f :: cat Integer Integer)) (Apply2 (g :: cat Integer Integer)) -> eq2 (f . g) (g . f)
+
+#endif
+
+#endif
+
diff --git a/src/Test/QuickCheck/Classes/Enum.hs b/src/Test/QuickCheck/Classes/Enum.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/QuickCheck/Classes/Enum.hs
@@ -0,0 +1,77 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+{-# OPTIONS_GHC -Wall #-}
+
+module Test.QuickCheck.Classes.Enum
+  ( enumLaws
+  , boundedEnumLaws
+  ) where
+
+import Data.Proxy (Proxy)
+import Test.QuickCheck hiding ((.&.))
+import Test.QuickCheck.Property (Property)
+
+import Test.QuickCheck.Classes.Common (Laws(..), myForAllShrink)
+
+-- | Tests the following properties:
+--
+-- [/Succ Pred Identity/]
+--   @succ (pred x) ≡ x@
+-- [/Pred Succ Identity/]
+--   @pred (succ x) ≡ x@
+--
+-- This only works for @Enum@ types that are not bounded, meaning
+-- that 'succ' and 'pred' must be total. This means that these property
+-- tests work correctly for types like 'Integer' but not for 'Int'.
+--
+-- Sadly, there is not a good way to test 'fromEnum' and 'toEnum',
+-- since many types that have reasonable implementations for 'succ'
+-- and 'pred' have more inhabitants than 'Int' does.
+enumLaws :: (Enum a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
+enumLaws p = Laws "Enum"
+  [ ("Succ Pred Identity", succPredIdentity p)
+  , ("Pred Succ Identity", predSuccIdentity p)
+  ]
+
+-- | Tests the same properties as 'enumLaws' except that it requires
+-- the type to have a 'Bounded' instance. These tests avoid taking the
+-- successor of the maximum element or the predecessor of the minimal
+-- element.
+boundedEnumLaws :: (Enum a, Bounded a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
+boundedEnumLaws p = Laws "Enum"
+  [ ("Succ Pred Identity", succPredBoundedIdentity p)
+  , ("Pred Succ Identity", predSuccBoundedIdentity p)
+  ]
+
+succPredIdentity :: forall a. (Enum a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+succPredIdentity _ = myForAllShrink False (const True)
+  (\(a :: a) -> ["a = " ++ show a])
+  "succ (pred x)"
+  (\a -> succ (pred a))
+  "x"
+  (\a -> a)
+
+predSuccIdentity :: forall a. (Enum a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+predSuccIdentity _ = myForAllShrink False (const True)
+  (\(a :: a) -> ["a = " ++ show a])
+  "pred (succ x)"
+  (\a -> pred (succ a))
+  "x"
+  (\a -> a)
+
+succPredBoundedIdentity :: forall a. (Enum a, Bounded a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+succPredBoundedIdentity _ = myForAllShrink False (\a -> a /= minBound)
+  (\(a :: a) -> ["a = " ++ show a])
+  "succ (pred x)"
+  (\a -> succ (pred a))
+  "x"
+  (\a -> a)
+
+predSuccBoundedIdentity :: forall a. (Enum a, Bounded a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+predSuccBoundedIdentity _ = myForAllShrink False (\a -> a /= maxBound)
+  (\(a :: a) -> ["a = " ++ show a])
+  "pred (succ x)"
+  (\a -> pred (succ a))
+  "x"
+  (\a -> a)
+
diff --git a/src/Test/QuickCheck/Classes/MonadFail.hs b/src/Test/QuickCheck/Classes/MonadFail.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/QuickCheck/Classes/MonadFail.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+{-# OPTIONS_GHC -Wall #-}
+
+module Test.QuickCheck.Classes.MonadFail
+  (
+#if MIN_VERSION_base(4,9,0) && MIN_VERSION_transformers(0,4,0)
+    monadFailLaws
+#endif  
+  ) where
+
+import Control.Applicative
+import Test.QuickCheck hiding ((.&.))
+#if MIN_VERSION_QuickCheck(2,10,0)
+import Control.Monad (ap)
+import Test.QuickCheck.Arbitrary (Arbitrary1(..))
+#if MIN_VERSION_base(4,9,0) && MIN_VERSION_transformers(0,4,0)
+import Data.Functor.Classes
+import Prelude hiding (fail)
+import Control.Monad.Fail (MonadFail(..))
+#endif
+#endif
+import Test.QuickCheck.Property (Property)
+
+import Test.QuickCheck.Classes.Common
+
+#if MIN_VERSION_QuickCheck(2,10,0)
+
+#if MIN_VERSION_base(4,9,0) && MIN_VERSION_transformers(0,4,0)
+
+-- | Tests the following 'MonadFail' properties:
+-- 
+-- [/Left Zero/]
+-- @'fail' s '>>=' f ≡ 'fail' s@
+monadFailLaws :: (MonadFail f, Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Laws
+monadFailLaws p = Laws "Monad"
+  [ ("Left Zero", monadFailLeftZero p)
+  ]
+ 
+monadFailLeftZero :: forall proxy f. (MonadFail f, Functor f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property
+monadFailLeftZero _ = property $ \(k' :: LinearEquationM f) (s :: String) ->
+  let k = runLinearEquationM k'
+  in eq1 (fail s >>= k) (fail s)
+
+#endif
+
+#endif
+
diff --git a/src/Test/QuickCheck/Classes/Storable.hs b/src/Test/QuickCheck/Classes/Storable.hs
--- a/src/Test/QuickCheck/Classes/Storable.hs
+++ b/src/Test/QuickCheck/Classes/Storable.hs
@@ -26,6 +26,12 @@
 
 import Test.QuickCheck.Classes.Common (Laws(..))
 
+-- | Tests the following alternative properties:
+--
+-- [/Set-Get/]
+--   @'runST' ('pokeElemOff' ptr ix a >> 'peekElemOff' ptr ix') ≡  a@
+-- [/Get-Set/]
+--   @'runST' ('peekElemOff' ptr ix >> 'pokeElemOff' ptr ix a) ≡ a@
 storableLaws :: (Storable a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
 storableLaws p = Laws "Storable"
   [ ("Set-Get (you get back what you put in)", storableSetGet p)
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -3,6 +3,7 @@
 {-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE DeriveFunctor #-}
 
 import Control.Monad
 import Control.Monad.Zip (MonadZip)
@@ -12,8 +13,19 @@
 #endif
 import Data.Bits
 import Data.Foldable
+#if defined(VERSION_containers)
+import Data.Map (Map)
+#endif
+#if MIN_VERSION_containers(0,5,9)
+import qualified Data.Map.Merge.Strict as MM
+#endif
 import Data.Traversable
 #if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
+#if defined(VERSION_semigroupoids)
+import Data.Functor.Apply (Apply((<.>)))
+#endif
+#endif
+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
 import Data.Functor.Classes
 #endif
 import Data.Int
@@ -24,6 +36,7 @@
 import Data.Word
 import Foreign.Storable
 import Test.QuickCheck
+import Text.Show.Functions
 
 import qualified Data.Vector as V
 import qualified Data.Foldable as F
@@ -31,7 +44,9 @@
 import Test.QuickCheck.Classes
 
 main :: IO ()
-main = lawsCheckMany allPropsApplied
+main = do
+  quickCheck prop_map_apply_equals
+  lawsCheckMany allPropsApplied
 
 allPropsApplied :: [(String,[Laws])]
 allPropsApplied = 
@@ -44,6 +59,14 @@
   , ("List",allHigherLaws (Proxy1 :: Proxy1 []))
 #endif
 #endif
+#if MIN_VERSION_QuickCheck(2,10,0)
+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
+#if defined(VERSION_semigroupoids)
+  , ("Map", someHigherLaws (Proxy1 :: Proxy1 (Map Int)))
+  , ("Pound", someHigherLaws (Proxy1 :: Proxy1 (Pound Int)))
+#endif
+#endif
+#endif
 #if MIN_VERSION_base(4,7,0)
   , ("Vector",[isListLaws (Proxy :: Proxy (Vector Word))])
 #endif
@@ -57,6 +80,8 @@
   , Arbitrary a
   , Show a
   , Read a
+  , Enum a
+  , Bounded a
 #if defined(VERSION_aeson)
   , ToJSON a
   , FromJSON a
@@ -71,6 +96,7 @@
   , semigroupLaws (Proxy :: Proxy (Sum a))
   , monoidLaws (Proxy :: Proxy (Sum a))
   , showReadLaws p
+  , boundedEnumLaws p
 #if defined(VERSION_aeson)
   , jsonLaws p
 #endif
@@ -100,6 +126,17 @@
 #endif
 #endif
 
+#if MIN_VERSION_QuickCheck(2,10,0)
+#if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
+#if defined(VERSION_semigroupoids)
+someHigherLaws :: (Apply f, Eq1 f, Arbitrary1 f, Show1 f) => proxy f -> [Laws]
+someHigherLaws p = 
+  [ applyLaws p
+  ]
+#endif
+#endif
+#endif
+
 -- This type fails the laws for the strict functions
 -- in Foldable. It is used just to confirm that
 -- those property tests actually work.
@@ -118,6 +155,40 @@
 #if MIN_VERSION_base(4,6,0)
   foldl' f x (Rouge xs) = F.foldl f x xs
   foldr' f x (Rouge xs) = F.foldr f x xs
+#endif
+
+newtype Pound k v = Pound { getPound :: Map k v }
+#if MIN_VERSION_QuickCheck(2,10,0) && (MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0))
+  deriving (Eq,Functor,Show,Arbitrary,Arbitrary1,Eq1,Show1)
+#else
+  deriving (Eq,Show,Arbitrary)
+#endif
+
+#if defined(VERSION_semigroupoids)
+#if MIN_VERSION_containers(0,5,9)
+instance Ord k => Apply (Pound k) where
+  Pound m1 <.> Pound m2 = Pound $
+    MM.merge
+      MM.dropMissing
+      MM.dropMissing
+      (MM.zipWithMatched (\_ f a -> f a))
+      m1
+      m2
+#endif
+#endif
+
+#if defined(VERSION_semigroupoids)
+#if MIN_VERSION_containers(0,5,9)
+prop_map_apply_equals :: Map Int (Int -> Int)
+                      -> Map Int Int
+                      -> Bool
+prop_map_apply_equals mf ma =
+  let pf = Pound mf
+      pa = Pound ma
+      m = mf <.> ma
+      p = pf <.> pa
+  in m == (getPound p)
+#endif
 #endif
 
 -------------------
