diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 56fdc43ae6a6d153d7fc81f4eb6e65d809d22963..7fe7a17d335eabfb1c70e6d3c81b63b441ee8dd9 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -3928,6 +3928,7 @@ xFlagsDeps = [
   flagSpec "DuplicateRecordFields"            LangExt.DuplicateRecordFields,
   flagSpec "EmptyCase"                        LangExt.EmptyCase,
   flagSpec "EmptyDataDecls"                   LangExt.EmptyDataDecls,
+  flagSpec "EmptyDataDeriving"                LangExt.EmptyDataDeriving,
   flagSpec "ExistentialQuantification"        LangExt.ExistentialQuantification,
   flagSpec "ExplicitForAll"                   LangExt.ExplicitForAll,
   flagSpec "ExplicitNamespaces"               LangExt.ExplicitNamespaces,
diff --git a/compiler/main/ErrUtils.hs b/compiler/main/ErrUtils.hs
index 5010a29513d4a5ecbeb1ed866fccbf00359f7514..258fc1170960f13ab21bfa3f68c1b15ddc0b50c8 100644
--- a/compiler/main/ErrUtils.hs
+++ b/compiler/main/ErrUtils.hs
@@ -10,7 +10,7 @@
 
 module ErrUtils (
         -- * Basic types
-        Validity(..), andValid, allValid, isValid, getInvalids,
+        Validity(..), andValid, allValid, isValid, getInvalids, orValid,
         Severity(..),
 
         -- * Messages
@@ -110,6 +110,10 @@ allValid (v : vs) = v `andValid` allValid vs
 getInvalids :: [Validity] -> [MsgDoc]
 getInvalids vs = [d | NotValid d <- vs]
 
+orValid :: Validity -> Validity -> Validity
+orValid IsValid _ = IsValid
+orValid _       v = v
+
 -- -----------------------------------------------------------------------------
 -- Basic error messages: just render a message with a source location.
 
diff --git a/compiler/typecheck/TcDerivUtils.hs b/compiler/typecheck/TcDerivUtils.hs
index f27516258bcd87b163caf42583cd3be303319228..d6b02dcf0038f56d1d79b8646ed9bf680ac99bf8 100644
--- a/compiler/typecheck/TcDerivUtils.hs
+++ b/compiler/typecheck/TcDerivUtils.hs
@@ -458,7 +458,7 @@ sideConditions mtheta cls
   | cls_key == ixClassKey          = Just (cond_std `andCond` cond_enumOrProduct cls)
   | cls_key == boundedClassKey     = Just (cond_std `andCond` cond_enumOrProduct cls)
   | cls_key == dataClassKey        = Just (checkFlag LangExt.DeriveDataTypeable `andCond`
-                                           cond_std `andCond`
+                                           cond_vanilla `andCond`
                                            cond_args cls)
   | cls_key == functorClassKey     = Just (checkFlag LangExt.DeriveFunctor `andCond`
                                            cond_vanilla `andCond`
@@ -521,13 +521,18 @@ cond_stdOK (Just _) _ _ _
   = IsValid     -- Don't check these conservative conditions for
                 -- standalone deriving; just generate the code
                 -- and let the typechecker handle the result
-cond_stdOK Nothing permissive _ rep_tc
+cond_stdOK Nothing permissive dflags rep_tc
   | null data_cons
-  , not permissive      = NotValid (no_cons_why rep_tc $$ suggestion)
-  | not (null con_whys) = NotValid (vcat con_whys $$ suggestion)
+  , not permissive = checkFlag LangExt.EmptyDataDeriving dflags rep_tc
+                     `orValid`
+                     NotValid (no_cons_why rep_tc $$ empty_data_suggestion)
+  | not (null con_whys) = NotValid (vcat con_whys $$ standalone_suggestion)
   | otherwise           = IsValid
   where
-    suggestion = text "Possible fix: use a standalone deriving declaration instead"
+    empty_data_suggestion =
+      text "Use EmptyDataDeriving to enable deriving for empty data types"
+    standalone_suggestion =
+      text "Possible fix: use a standalone deriving declaration instead"
     data_cons  = tyConDataCons rep_tc
     con_whys   = getInvalids (map check_con data_cons)
 
diff --git a/compiler/typecheck/TcGenDeriv.hs b/compiler/typecheck/TcGenDeriv.hs
index 70ceb3030586112bfe459e1aa5b9b8ac60475eb3..d9166e5e002adf46aca92d28e47bcff9efa8ef75 100644
--- a/compiler/typecheck/TcGenDeriv.hs
+++ b/compiler/typecheck/TcGenDeriv.hs
@@ -194,8 +194,9 @@ gen_Eq_binds loc tycon = do
               | otherwise         = unitBag $ DerivAuxBind $ DerivCon2Tag tycon
 
     method_binds dflags = unitBag (eq_bind dflags)
-    eq_bind dflags = mkFunBindSE 2 loc eq_RDR (map pats_etc pat_match_cons
-                                            ++ fall_through_eqn dflags)
+    eq_bind dflags = mkFunBindEC 2 loc eq_RDR (const true_Expr)
+                                 (map pats_etc pat_match_cons
+                                   ++ fall_through_eqn dflags)
 
     ------------------------------------------------------------------
     pats_etc data_con
@@ -339,7 +340,7 @@ gen_Ord_binds :: SrcSpan -> TyCon -> TcM (LHsBinds GhcPs, BagDerivStuff)
 gen_Ord_binds loc tycon = do
     dflags <- getDynFlags
     return $ if null tycon_data_cons -- No data-cons => invoke bale-out case
-      then ( unitBag $ mkFunBindSE 2 loc compare_RDR []
+      then ( unitBag $ mkFunBindEC 2 loc compare_RDR (const eqTag_Expr) []
            , emptyBag)
       else ( unitBag (mkOrdOp dflags OrdCompare) `unionBags` other_ops dflags
            , aux_binds)
@@ -961,11 +962,15 @@ gen_Read_binds get_fixity loc tycon
     data_cons = tyConDataCons tycon
     (nullary_cons, non_nullary_cons) = partition isNullarySrcDataCon data_cons
 
-    read_prec = mkHsVarBind loc readPrec_RDR
-                              (nlHsApp (nlHsVar parens_RDR) read_cons)
+    read_prec = mkHsVarBind loc readPrec_RDR rhs
+      where
+        rhs | null data_cons -- See Note [Read for empty data types]
+            = nlHsVar pfail_RDR
+            | otherwise
+            = nlHsApp (nlHsVar parens_RDR)
+                      (foldr1 mk_alt (read_nullary_cons ++
+                                      read_non_nullary_cons))
 
-    read_cons | null data_cons = nlHsVar pfail_RDR  -- See Note [Read for empty data types]
-              | otherwise      = foldr1 mk_alt (read_nullary_cons ++ read_non_nullary_cons)
     read_non_nullary_cons = map read_non_nullary_con non_nullary_cons
 
     read_nullary_cons
@@ -1127,7 +1132,7 @@ gen_Show_binds get_fixity loc tycon
   = (unitBag shows_prec, emptyBag)
   where
     data_cons = tyConDataCons tycon
-    shows_prec = mkFunBindSE 1 loc showsPrec_RDR (map pats_etc data_cons)
+    shows_prec = mkFunBindEC 1 loc showsPrec_RDR id (map pats_etc data_cons)
     comma_space = nlHsVar showCommaSpace_RDR
 
     pats_etc data_con
@@ -1348,7 +1353,7 @@ gen_data dflags data_type_name constr_names loc rep_tc
                | otherwise = prefix_RDR
 
         ------------ gfoldl
-    gfoldl_bind = mkFunBindSE 3 loc gfoldl_RDR (map gfoldl_eqn data_cons)
+    gfoldl_bind = mkFunBindEC 3 loc gfoldl_RDR id (map gfoldl_eqn data_cons)
 
     gfoldl_eqn con
       = ([nlVarPat k_RDR, z_Pat, nlConVarPat con_name as_needed],
@@ -1384,7 +1389,7 @@ gen_data dflags data_type_name constr_names loc rep_tc
         tag = dataConTag dc
 
         ------------ toConstr
-    toCon_bind = mkFunBindSE 1 loc toConstr_RDR
+    toCon_bind = mkFunBindEC 1 loc toConstr_RDR id
                      (zipWith to_con_eqn data_cons constr_names)
     to_con_eqn dc con_name = ([nlWildConPat dc], nlHsVar con_name)
 
@@ -1519,23 +1524,11 @@ makeG_d.
 -}
 
 gen_Lift_binds :: SrcSpan -> TyCon -> (LHsBinds GhcPs, BagDerivStuff)
-gen_Lift_binds loc tycon
-  | null data_cons = (unitBag (L loc $ mkFunBind (L loc lift_RDR)
-                       [mkMatch (mkPrefixFunRhs (L loc lift_RDR))
-                                        [nlWildPat] errorMsg_Expr
-                                        (noLoc emptyLocalBinds)])
-                     , emptyBag)
-  | otherwise = (unitBag lift_bind, emptyBag)
+gen_Lift_binds loc tycon = (unitBag lift_bind, emptyBag)
   where
-    -- We may want to make mkFunBindSE's error message generation general
-    -- enough to avoid needing to duplicate its logic here. On the other
-    -- hand, it may not be worth the trouble.
-    errorMsg_Expr = nlHsVar error_RDR `nlHsApp` nlHsLit
-        (mkHsString $ "Can't lift value of empty datatype " ++ tycon_str)
-
-    lift_bind = mkFunBindSE 1 loc lift_RDR (map pats_etc data_cons)
+    lift_bind = mkFunBindEC 1 loc lift_RDR (nlHsApp pure_Expr)
+                            (map pats_etc data_cons)
     data_cons = tyConDataCons tycon
-    tycon_str = occNameString . nameOccName . tyConName $ tycon
 
     pats_etc data_con
       = ([con_pat], lift_Expr)
@@ -1865,6 +1858,21 @@ mkRdrFunBind :: Located RdrName -> [LMatch GhcPs (LHsExpr GhcPs)]
 mkRdrFunBind fun@(L loc _fun_rdr) matches
   = L loc (mkFunBind fun matches)
 
+-- | Make a function binding. If no equations are given, produce a function
+-- with the given arity that uses an empty case expression for the last
+-- argument that is passes to the given function to produce the right-hand
+-- side.
+mkFunBindEC :: Arity -> SrcSpan -> RdrName
+            -> (LHsExpr GhcPs -> LHsExpr GhcPs)
+            -> [([LPat GhcPs], LHsExpr GhcPs)]
+            -> LHsBind GhcPs
+mkFunBindEC arity loc fun catch_all pats_and_exprs
+  = mkRdrFunBindEC arity catch_all (L loc fun) matches
+  where
+    matches = [ mkMatch (mkPrefixFunRhs (L loc fun)) p e
+                                (noLoc emptyLocalBinds)
+              | (p,e) <- pats_and_exprs ]
+
 -- | Produces a function binding. When no equations are given, it generates
 -- a binding of the given arity and an empty case expression
 -- for the last argument that it passes to the given function to produce
@@ -2115,7 +2123,7 @@ bs_RDRs         = [ mkVarUnqual (mkFastString ("b"++show i)) | i <- [(1::Int) ..
 cs_RDRs         = [ mkVarUnqual (mkFastString ("c"++show i)) | i <- [(1::Int) .. ] ]
 
 a_Expr, b_Expr, c_Expr, z_Expr, ltTag_Expr, eqTag_Expr, gtTag_Expr, false_Expr,
-    true_Expr :: LHsExpr GhcPs
+    true_Expr, pure_Expr :: LHsExpr GhcPs
 a_Expr          = nlHsVar a_RDR
 b_Expr          = nlHsVar b_RDR
 c_Expr          = nlHsVar c_RDR
@@ -2125,6 +2133,7 @@ eqTag_Expr      = nlHsVar eqTag_RDR
 gtTag_Expr      = nlHsVar gtTag_RDR
 false_Expr      = nlHsVar false_RDR
 true_Expr       = nlHsVar true_RDR
+pure_Expr       = nlHsVar pure_RDR
 
 a_Pat, b_Pat, c_Pat, d_Pat, k_Pat, z_Pat :: LPat GhcPs
 a_Pat           = nlVarPat a_RDR
diff --git a/docs/users_guide/8.4.1-notes.rst b/docs/users_guide/8.4.1-notes.rst
index 4ed70280eb9158d40337ab5d9d4c421001e46894..d7e5d6d61e260baa92d91c27bce179d684a7cd13 100644
--- a/docs/users_guide/8.4.1-notes.rst
+++ b/docs/users_guide/8.4.1-notes.rst
@@ -88,6 +88,18 @@ Language
   order that the users writes them, so the type of ``MkT`` is now
   ``forall b a. b -> T a`` (this matters for :ghc-flag:`-XTypeApplications`).
 
+- The new :ghc-flag:`-XEmptyDataDeriving` extension allows deriving ``Eq``,
+  ``Ord``, ``Read``, and ``Show`` instances directly for empty data types, as
+  in ``data Empty deriving Eq``. (Previously, this would require the use of
+  :ghc-flag:`-XStandaloneDeriving` to accomplish.)
+
+  One can also now derive ``Data`` instances directly for empty data types (as
+  in ``data Empty deriving Data``) without needing to use
+  :ghc-flag:`-XStandaloneDeriving`. However, since already requires a GHC
+  extension (:ghc-flag:`-XDeriveDataTypeable`), one does not need to enable
+  :ghc-flag:`-XEmptyDataDeriving` to do so. This also goes for other classes
+  which require extensions to derive, such as :ghc-flag:`-XDeriveFunctor`.
+
 Compiler
 ~~~~~~~~
 
@@ -112,36 +124,112 @@ Compiler
   See also :ref:`deriving-functor`, :ref:`deriving-foldable`, and
   :ref:`deriving-traversable`.
 
-- Derived ``Functor``, ``Foldable``, ``Traversable``, ``Generic``, and
-  ``Generic1`` instances now have better, and generally better-documented,
-  behaviors for types with no constructors. In particular, ::
+- Derived instances for empty data types are now substantially different
+  than before. Here is an overview of what has changed. These examples will
+  use a running example of ``data Empty a`` to describe what happens when an
+  instance is derived for ``Empty``:
 
-      fmap _ x = case x of
-      foldMap _ _ = mempty
-      traverse _ x = pure (case x of)
-      to x = case x of
-      to1 x = case x of
-      from x = case x of
-      from1 x = case x of
+  - Derived ``Eq`` and ``Ord`` instances would previously emit code that used
+    ``error``: ::
 
-  The new behavior generally leads to more useful error messages than the
-  old did, and lazier semantics for ``foldMap`` and ``traverse``.
+      instance Eq (Empty a) where
+        (==) = error "Void =="
 
-- Derived ``Foldable`` instances now derive custom definitions for ``null``
-  instead of using the default one. This leads to asymptotically better
-  performance for recursive types not shaped like cons-lists, and allows ``null``
-  to terminate for more (but not all) infinitely large structures.
+      instance Ord (Empty a) where
+        compare = error "Void compare"
+
+    Now, they emit code that uses maximally defined, lazier semantics: ::
+
+      instance Eq (Empty a) where
+        _ == _ = True
+
+      instance Ord (Empty a) where
+        compare _ _ = EQ
+
+  - Derived ``Read`` instances would previous emit code that used
+    ``parens``: ::
+
+      instance Read (Empty a) where
+        readPrec = parens pfail
+
+    But ``parens`` forces parts of the parsed string that it doesn't need to.
+    Now, the derived instance will not use ``parens`` (that it, parsing
+    ``Empty`` will always fail, without reading *any* input): ::
+
+      instance Read (Empty a) where
+        readPrec = pfail
+
+  - Derived ``Show`` instances would previously emit code that used
+    ``error``: ::
+
+      instance Show (Empty a) where
+        showsPrec = "Void showsPrec"
+
+    Now, they emit code that inspects the argument. That is, if the argument
+    diverges, then showing it will also diverge: ::
+
+      instance Show (Empty a) where
+        showsPrec _ x = case x of {}
+
+  - Derived ``Functor``, ``Foldable``, ``Traversable``, ``Generic``,
+    ``Generic1``, ``Lift``, and ``Data`` instances previously emitted code that
+    used ``error``: ::
 
-- Derived instances for types with no constructors now have appropriate
-  arities: they take all their arguments before producing errors. This may not
-  be terribly important in practice, but it seems like the right thing to do.
-  Previously, we generated ::
+      instance Functor Empty where
+        fmap = error "Void fmap"
 
-      (==) = error ...
+      instance Foldable Empty where
+        foldMap = error "Void foldMap"
 
-Now we generate ::
+      instance Traversable Empty where
+        traverse = error "Void traverse"
 
-      _ == _ = error ...
+      instance Generic (Empty a) where
+        from = M1 (error "No generic representation for empty datatype Empty")
+        to (M1 _) = error "No values for empty datatype Empty"
+      -- Similarly for Generic1
+
+      instance Lift (Empty a) where
+        lift _ = error "Can't lift value of empty datatype Empty"
+
+      instance Data a => Data (Empty a) where
+        gfoldl _ _ _ = error "Void gfoldl"
+        toConstr _ = error "Void toConstr"
+        ...
+
+    Now, derived ``Functor``, ``Traversable, ``Generic``, ``Generic1``,
+    ``Lift``, and ``Data`` instances emit code which inspects their
+    arguments: ::
+
+      instance Functor Empty where
+        fmap _ x = case x of {}
+
+      instance Traversable Empty where
+        traverse _ x = pure (case x of {})
+
+      instance Generic (Empty a) where
+        from x = M1 (case x of {})
+        to (M1 x) = case x of {}
+
+      -- Similarly for Generic1
+
+      instance Lift (Empty a) where
+        lift x = pure (case x of {})
+
+      instance Data a => Data (Empty a) where
+        gfoldl _ x = case x of {}
+        toConstr x = case x of {}
+        ...
+
+    Derived ``Foldable`` instances now are maximally lazy: ::
+
+      instance Foldable Empty where
+        foldMap _ _ = mempty
+
+- Derived ``Foldable`` instances now derive custom definitions for ``null``
+  instead of using the default one. This leads to asymptotically better
+  performance for recursive types not shaped like cons-lists, and allows ``null``
+  to terminate for more (but not all) infinitely large structures.
 
 - `-fsplit-sections` is now supported on x86_64 Windows and is on by default.
   See :ghc-ticket:`12913`.
diff --git a/docs/users_guide/glasgow_exts.rst b/docs/users_guide/glasgow_exts.rst
index 492b105764d9c1947d5d2784d96187e9b48595c7..06f2263a736e3313b1cf8af522fe77c7618bd04d 100644
--- a/docs/users_guide/glasgow_exts.rst
+++ b/docs/users_guide/glasgow_exts.rst
@@ -2087,6 +2087,10 @@ then an explicit kind annotation must be used (see :ref:`kinding`).
 Such data types have only one value, namely bottom. Nevertheless, they
 can be useful when defining "phantom types".
 
+In conjunction with the :ghc-flag:`-XEmptyDataDeriving` extension, empty data
+declarations can also derive instances of standard type classes
+(see :ref:`empty-data-deriving`).
+
 .. _datatype-contexts:
 
 Data type contexts
@@ -3554,6 +3558,54 @@ GHC extends this mechanism along several axes:
   <#deriving-stragies>`__, especially if the compiler chooses the wrong
   one `by default <#default-deriving-strategy>`__.
 
+.. _empty-data-deriving:
+
+Deriving instances for empty data types
+---------------------------------------
+
+.. ghc-flag:: -XEmptyDataDeriving
+    :shortdesc: Allow deriving instances of standard type classes for
+                empty data types.
+    :type: dynamic
+    :reverse: -XNoEmptyDataDeriving
+    :category:
+
+    :since: 8.4.1
+
+    Allow deriving instances of standard type classes for empty data types.
+
+One can write data types with no constructors using the
+:ghc-flag:`-XEmptyDataDecls` flag (see :ref:`nullary-types`), which is on by
+default in Haskell 2010. What is not on by default is the ability to derive
+type class instances for these types. This ability is enabled through use of
+the :ghc-flag:`-XEmptyDataDeriving` flag. For instance, this lets one write: ::
+
+    data Empty deriving (Eq, Ord, Read, Show)
+
+This would generate the following instances: ::
+
+    instance Eq Empty where
+      _ == _ = True
+
+    instance Ord Empty where
+      compare _ _ = EQ
+
+    instance Read Empty where
+      readPrec = pfail
+
+    instance Show Empty where
+      showsPrec _ x = case x of {}
+
+The :ghc-flag:`-XEmptyDataDeriving` flag is only required to enable deriving
+of these four "standard" type classes (which are mentioned in the Haskell
+Report). Other extensions to the ``deriving`` mechanism, which are explained
+below in greater detail, do not require :ghc-flag:`-XEmptyDataDeriving` to be
+used in conjunction with empty data types. These include:
+
+* :ghc-flag:`-XStandaloneDeriving` (see :ref:`stand-alone-deriving`)
+* Type classes which require their own extensions to be enabled to be derived,
+  such as :ghc-flag:`-XDeriveFunctor` (see :ref:`deriving-extra`)
+* :ghc-flag:`-XDeriveAnyClass` (see :ref:`derive-any-class`)
 
 .. _deriving-inferred:
 
diff --git a/libraries/base/Data/Void.hs b/libraries/base/Data/Void.hs
index ed3cfbc3306466cd4a04f2d57df2eab1d180a7e8..beb6041f626aa67eeb1fef428ea4e582fc674468 100644
--- a/libraries/base/Data/Void.hs
+++ b/libraries/base/Data/Void.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE EmptyCase #-}
+{-# LANGUAGE EmptyDataDeriving #-}
 {-# LANGUAGE Safe #-}
 {-# LANGUAGE StandaloneDeriving #-}
 
@@ -33,27 +34,17 @@ import Data.Semigroup (Semigroup(..), stimesIdempotent)
 -- | Uninhabited data type
 --
 -- @since 4.8.0.0
-data Void deriving (Generic)
-
-deriving instance Data Void
-
--- | @since 4.8.0.0
-instance Eq Void where
-    _ == _ = True
-
--- | @since 4.8.0.0
-instance Ord Void where
-    compare _ _ = EQ
-
--- | Reading a 'Void' value is always a parse error, considering
--- 'Void' as a data type with no constructors.
--- | @since 4.8.0.0
-instance Read Void where
-    readsPrec _ _ = []
-
--- | @since 4.8.0.0
-instance Show Void where
-    showsPrec _ = absurd
+data Void deriving
+  ( Eq      -- ^ @since 4.8.0.0
+  , Data    -- ^ @since 4.8.0.0
+  , Generic -- ^ @since 4.8.0.0
+  , Ord     -- ^ @since 4.8.0.0
+  , Read    -- ^ Reading a 'Void' value is always a parse error, considering
+            -- 'Void' as a data type with no constructors.
+            --
+            -- @since 4.8.0.0
+  , Show    -- ^ @since 4.8.0.0
+  )
 
 -- | @since 4.8.0.0
 instance Ix Void where
diff --git a/libraries/base/GHC/Generics.hs b/libraries/base/GHC/Generics.hs
index 3bb2299f32d9155ac9aa8c5ed8e4221a43783b09..3ae9a2cec5a4c3010e1646638de260340855cd0c 100644
--- a/libraries/base/GHC/Generics.hs
+++ b/libraries/base/GHC/Generics.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE DataKinds                  #-}
 {-# LANGUAGE DeriveFunctor              #-}
 {-# LANGUAGE DeriveGeneric              #-}
+{-# LANGUAGE EmptyDataDeriving          #-}
 {-# LANGUAGE FlexibleContexts           #-}
 {-# LANGUAGE FlexibleInstances          #-}
 {-# LANGUAGE GADTs                      #-}
@@ -755,12 +756,14 @@ import GHC.TypeLits ( Nat, Symbol, KnownSymbol, KnownNat, symbolVal, natVal )
 
 -- | Void: used for datatypes without constructors
 data V1 (p :: k)
-  deriving (Functor, Generic, Generic1)
-
-deriving instance Eq   (V1 p)
-deriving instance Ord  (V1 p)
-deriving instance Read (V1 p)
-deriving instance Show (V1 p)
+  deriving ( Eq       -- ^ @since 4.9.0.0
+           , Ord      -- ^ @since 4.9.0.0
+           , Read     -- ^ @since 4.9.0.0
+           , Show     -- ^ @since 4.9.0.0
+           , Functor  -- ^ @since 4.9.0.0
+           , Generic  -- ^ @since 4.9.0.0
+           , Generic1 -- ^ @since 4.9.0.0
+           )
 
 -- | Unit: used for constructors without arguments
 data U1 (p :: k) = U1
diff --git a/libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs b/libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs
index ff26ec6ce7620a42832a9728c1e602d91243d5f3..1979838a0756e1c0652dbabec4c707ccd44494a2 100644
--- a/libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs
+++ b/libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs
@@ -131,4 +131,5 @@ data Extension
    | Strict
    | StrictData
    | MonadFailDesugaring
+   | EmptyDataDeriving
    deriving (Eq, Enum, Show, Generic)
diff --git a/testsuite/tests/deriving/should_compile/drv-empty-data.stderr b/testsuite/tests/deriving/should_compile/drv-empty-data.stderr
index 47d5a984abbf862c43fc088567f4efabddf062a4..e131c1cf5b6fbb0563d06529e760ceafa932f0c7 100644
--- a/testsuite/tests/deriving/should_compile/drv-empty-data.stderr
+++ b/testsuite/tests/deriving/should_compile/drv-empty-data.stderr
@@ -2,25 +2,24 @@
 ==================== Derived instances ====================
 Derived class instances:
   instance GHC.Read.Read (DrvEmptyData.Void a) where
-    GHC.Read.readPrec
-      = GHC.Read.parens Text.ParserCombinators.ReadPrec.pfail
+    GHC.Read.readPrec = Text.ParserCombinators.ReadPrec.pfail
     GHC.Read.readList = GHC.Read.readListDefault
     GHC.Read.readListPrec = GHC.Read.readListPrecDefault
   
   instance GHC.Show.Show (DrvEmptyData.Void a) where
-    GHC.Show.showsPrec _ = GHC.Err.error "Void showsPrec"
+    GHC.Show.showsPrec z = case z of
   
   instance GHC.Classes.Ord (DrvEmptyData.Void a) where
-    GHC.Classes.compare _ _ = GHC.Err.error "Void compare"
+    GHC.Classes.compare _ z = GHC.Types.EQ
   
   instance GHC.Classes.Eq (DrvEmptyData.Void a) where
-    (GHC.Classes.==) _ _ = GHC.Err.error "Void =="
+    (GHC.Classes.==) _ z = GHC.Types.True
   
   instance Data.Data.Data a =>
            Data.Data.Data (DrvEmptyData.Void a) where
-    Data.Data.gfoldl _ _ _ = GHC.Err.error "Void gfoldl"
+    Data.Data.gfoldl _ _ z = case z of
     Data.Data.gunfold k z c = case Data.Data.constrIndex c of
-    Data.Data.toConstr _ = GHC.Err.error "Void toConstr"
+    Data.Data.toConstr z = case z of
     Data.Data.dataTypeOf _ = DrvEmptyData.$tVoid
     Data.Data.dataCast1 f = Data.Typeable.gcast1 f
   
@@ -46,8 +45,7 @@ Derived class instances:
   
   instance Language.Haskell.TH.Syntax.Lift
              (DrvEmptyData.Void a) where
-    Language.Haskell.TH.Syntax.lift _
-      = GHC.Err.error "Can't lift value of empty datatype Void"
+    Language.Haskell.TH.Syntax.lift z = GHC.Base.pure (case z of)
   
   DrvEmptyData.$tVoid :: Data.Data.DataType
   DrvEmptyData.$tVoid = Data.Data.mkDataType "Void" []
@@ -65,3 +63,237 @@ Derived type family instances:
 
 
 ==================== Filling in method body ====================
+GHC.Read.Read [DrvEmptyData.Void a[ssk:2]]
+  GHC.Read.readsPrec = GHC.Read.$dmreadsPrec
+                         @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+GHC.Show.Show [DrvEmptyData.Void a[ssk:2]]
+  GHC.Show.show = GHC.Show.$dmshow @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+GHC.Show.Show [DrvEmptyData.Void a[ssk:2]]
+  GHC.Show.showList = GHC.Show.$dmshowList
+                        @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+GHC.Classes.Ord [DrvEmptyData.Void a[ssk:2]]
+  GHC.Classes.< = GHC.Classes.$dm< @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+GHC.Classes.Ord [DrvEmptyData.Void a[ssk:2]]
+  GHC.Classes.<= = GHC.Classes.$dm<= @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+GHC.Classes.Ord [DrvEmptyData.Void a[ssk:2]]
+  GHC.Classes.> = GHC.Classes.$dm> @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+GHC.Classes.Ord [DrvEmptyData.Void a[ssk:2]]
+  GHC.Classes.>= = GHC.Classes.$dm>= @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+GHC.Classes.Ord [DrvEmptyData.Void a[ssk:2]]
+  GHC.Classes.max = GHC.Classes.$dmmax @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+GHC.Classes.Ord [DrvEmptyData.Void a[ssk:2]]
+  GHC.Classes.min = GHC.Classes.$dmmin @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+GHC.Classes.Eq [DrvEmptyData.Void a[ssk:2]]
+  GHC.Classes./= = GHC.Classes.$dm/= @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Data.Data [DrvEmptyData.Void a[ssk:2]]
+  Data.Data.dataCast2 = Data.Data.$dmdataCast2
+                          @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Data.Data [DrvEmptyData.Void a[ssk:2]]
+  Data.Data.gmapT = Data.Data.$dmgmapT @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Data.Data [DrvEmptyData.Void a[ssk:2]]
+  Data.Data.gmapQl = Data.Data.$dmgmapQl
+                       @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Data.Data [DrvEmptyData.Void a[ssk:2]]
+  Data.Data.gmapQr = Data.Data.$dmgmapQr
+                       @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Data.Data [DrvEmptyData.Void a[ssk:2]]
+  Data.Data.gmapQ = Data.Data.$dmgmapQ @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Data.Data [DrvEmptyData.Void a[ssk:2]]
+  Data.Data.gmapQi = Data.Data.$dmgmapQi
+                       @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Data.Data [DrvEmptyData.Void a[ssk:2]]
+  Data.Data.gmapM = Data.Data.$dmgmapM @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Data.Data [DrvEmptyData.Void a[ssk:2]]
+  Data.Data.gmapMp = Data.Data.$dmgmapMp
+                       @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Data.Data [DrvEmptyData.Void a[ssk:2]]
+  Data.Data.gmapMo = Data.Data.$dmgmapMo
+                       @(DrvEmptyData.Void a[ssk:2])
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.fold = Data.Foldable.$dmfold @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.foldr = Data.Foldable.$dmfoldr @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.foldr' = Data.Foldable.$dmfoldr' @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.foldl = Data.Foldable.$dmfoldl @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.foldl' = Data.Foldable.$dmfoldl' @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.foldr1 = Data.Foldable.$dmfoldr1 @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.foldl1 = Data.Foldable.$dmfoldl1 @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.toList = Data.Foldable.$dmtoList @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.null = Data.Foldable.$dmnull @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.length = Data.Foldable.$dmlength @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.elem = Data.Foldable.$dmelem @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.maximum = Data.Foldable.$dmmaximum
+                            @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.minimum = Data.Foldable.$dmminimum
+                            @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.sum = Data.Foldable.$dmsum @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Foldable.Foldable [DrvEmptyData.Void]
+  Data.Foldable.product = Data.Foldable.$dmproduct
+                            @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Traversable.Traversable [DrvEmptyData.Void]
+  Data.Traversable.sequenceA = Data.Traversable.$dmsequenceA
+                                 @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Traversable.Traversable [DrvEmptyData.Void]
+  Data.Traversable.mapM = Data.Traversable.$dmmapM
+                            @(DrvEmptyData.Void)
+
+
+
+==================== Filling in method body ====================
+Data.Traversable.Traversable [DrvEmptyData.Void]
+  Data.Traversable.sequence = Data.Traversable.$dmsequence
+                                @(DrvEmptyData.Void)
+
+
diff --git a/testsuite/tests/deriving/should_fail/T7401_fail.hs b/testsuite/tests/deriving/should_fail/T7401_fail.hs
new file mode 100644
index 0000000000000000000000000000000000000000..730223f17972127ee7025203cdd7966d1b7e482d
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T7401_fail.hs
@@ -0,0 +1,3 @@
+module T7401_fail where
+
+data D deriving Eq
diff --git a/testsuite/tests/deriving/should_fail/T7401_fail.stderr b/testsuite/tests/deriving/should_fail/T7401_fail.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..feb841f962c9b8d32839313853a2e7d514555975
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T7401_fail.stderr
@@ -0,0 +1,6 @@
+
+T7401_fail.hs:3:17: error:
+    • Can't make a derived instance of ‘Eq D’:
+        ‘D’ must have at least one data constructor
+        Use EmptyDataDeriving to enable deriving for empty data types
+    • In the data declaration for ‘D’
diff --git a/testsuite/tests/deriving/should_fail/all.T b/testsuite/tests/deriving/should_fail/all.T
index 1861e6dd0ad2002759ec61624d8a49487bd6e29d..c9b8469c3cbf35c5487022c2a831e6a957285796 100644
--- a/testsuite/tests/deriving/should_fail/all.T
+++ b/testsuite/tests/deriving/should_fail/all.T
@@ -44,6 +44,7 @@ test('T7148a', normal, compile_fail, [''])
 # T7800 was removed as it was out of date re: fixing #9858
 test('T5498', normal, compile_fail, [''])
 test('T6147', normal, compile_fail, [''])
+test('T7401_fail', normal, compile_fail, [''])
 test('T8165_fail1', normal, compile_fail, [''])
 test('T8165_fail2', normal, compile_fail, [''])
 test('T8851', normal, compile_fail, [''])
diff --git a/testsuite/tests/deriving/should_run/T5628.stderr b/testsuite/tests/deriving/should_run/T5628.stderr
deleted file mode 100644
index e203374673aedd0fc0904d7c7260ededa33e63e4..0000000000000000000000000000000000000000
--- a/testsuite/tests/deriving/should_run/T5628.stderr
+++ /dev/null
@@ -1,3 +0,0 @@
-T5628: Void ==
-CallStack (from ImplicitParams):
-  error, called at T5628.hs:5:1 in main:Main
diff --git a/testsuite/tests/deriving/should_run/T5628.stdout b/testsuite/tests/deriving/should_run/T5628.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..0ca95142bb715442d0c2c82a7c573a08c4593845
--- /dev/null
+++ b/testsuite/tests/deriving/should_run/T5628.stdout
@@ -0,0 +1 @@
+True
diff --git a/testsuite/tests/deriving/should_run/T7401.hs b/testsuite/tests/deriving/should_run/T7401.hs
new file mode 100644
index 0000000000000000000000000000000000000000..2f56df4e6919b2151d98e5bc3dbd9d7773887fc9
--- /dev/null
+++ b/testsuite/tests/deriving/should_run/T7401.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE EmptyDataDeriving #-}
+module Main where
+
+import Data.Function
+
+data Foo
+  deriving (Eq, Ord, Read, Show)
+
+foo1 :: Foo
+foo1 = fix id
+
+foo2 :: Foo
+foo2 = let x = y
+           y = x
+        in y
+
+main :: IO ()
+main = do
+  print (foo1 ==        foo2)
+  print (foo1 `compare` foo2)
diff --git a/testsuite/tests/deriving/should_run/T7401.stdout b/testsuite/tests/deriving/should_run/T7401.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..886c3aedacc96ae80cfb2a1deb79cee6ed39abda
--- /dev/null
+++ b/testsuite/tests/deriving/should_run/T7401.stdout
@@ -0,0 +1,2 @@
+True
+EQ
diff --git a/testsuite/tests/deriving/should_run/all.T b/testsuite/tests/deriving/should_run/all.T
index 3bcebdf371de7c8b99684c365010d47441dc657b..c5605f627e3ac9b4ae8929028e7267eb62ac6fb5 100644
--- a/testsuite/tests/deriving/should_run/all.T
+++ b/testsuite/tests/deriving/should_run/all.T
@@ -32,8 +32,9 @@ test('drvrun-foldable1', normal, compile_and_run, [''])
 test('T4136', normal, compile_and_run, [''])
 test('T4528a', normal, compile_and_run, [''])
 test('T5041', normal, compile_and_run, [''])
-test('T5628', exit_code(1), compile_and_run, [''])
+test('T5628', normal, compile_and_run, [''])
 test('T5712', normal, compile_and_run, [''])
+test('T7401', normal, compile_and_run, [''])
 test('T7931', normal, compile_and_run, [''])
 # T8280 is superseded by T10104
 test('T9576', exit_code(1), compile_and_run, [''])
diff --git a/testsuite/tests/driver/T4437.hs b/testsuite/tests/driver/T4437.hs
index 3ae39d1ca2feda67189f9cb98d210e27194106fc..c26a38861c31b8ed38cb04e8dd348a75aeea19ba 100644
--- a/testsuite/tests/driver/T4437.hs
+++ b/testsuite/tests/driver/T4437.hs
@@ -40,7 +40,8 @@ expectedGhcOnlyExtensions = ["RelaxedLayout",
                              "AlternativeLayoutRule",
                              "AlternativeLayoutRuleTransitional",
                              "UnboxedSums",
-                             "DerivingStrategies"]
+                             "DerivingStrategies",
+                             "EmptyDataDeriving"]
 
 expectedCabalOnlyExtensions :: [String]
 expectedCabalOnlyExtensions = ["Generics",