diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.4.1 (2023-02-22)
+  * add `DerivingVia` wrapper for generic instances (like `Generically`)
+
 ## 0.4.0 (2023-02-22)
   * redesign some instances to avoid the decomposer style
     * alter `Identity`, `Const` instances
diff --git a/src/Strongweak.hs b/src/Strongweak.hs
--- a/src/Strongweak.hs
+++ b/src/Strongweak.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE UndecidableInstances #-}
 module Strongweak
   (
   -- * Instance design
@@ -12,6 +13,14 @@
 import Strongweak.Strengthen
 
 {- $strongweak-instance-design
+
+A given strong type @a@ has exactly one associated weak type @'Weak' a@.
+Multiple strong types may weaken to the same weak type.
+
+The following laws must hold:
+
+  * @'weaken' a == 'weaken' b |= a == b@
+  * @'strengthen' ('weaken' a) == 'pure' a@
 
 strongweak is largely a programmer convenience library. There is a lot of room
 to write instances which may seem useful on first glance, but are inconsistent
diff --git a/src/Strongweak/Generic.hs b/src/Strongweak/Generic.hs
--- a/src/Strongweak/Generic.hs
+++ b/src/Strongweak/Generic.hs
@@ -8,10 +8,14 @@
   -- * Generic derivers
     weakenGeneric
   , strengthenGeneric
+
+  -- * Generic wrapper
+  , GenericallySW(..)
   ) where
 
 import Strongweak.Generic.Weaken
 import Strongweak.Generic.Strengthen
+import Strongweak.Generic.Via
 
 {- $generic-derivation-compatibility
 
diff --git a/src/Strongweak/Generic/Via.hs b/src/Strongweak/Generic/Via.hs
new file mode 100644
--- /dev/null
+++ b/src/Strongweak/Generic/Via.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE UndecidableInstances #-} -- required due to nested constraints
+
+module Strongweak.Generic.Via where
+
+import Strongweak.Generic.Weaken
+import Strongweak.Generic.Strengthen
+import Strongweak
+import GHC.Generics
+import Data.Kind
+
+{- | @DerivingVia@ wrapper for strongweak instances.
+
+We can't use 'Generically' conveniently because we need to talk about two data
+types, not one -- we would have to do something like @'Generically' ('Tagged' w
+s)@, which is ugly. So we instead define our own adorable little "via type"
+here!
+
+Use like so:
+
+@
+data XYZ (s :: Strength) = XYZ
+  { xyz1 :: SW s Word8
+  , xyz2 :: Word8
+  , xyz3 :: ()
+  } deriving stock Generic
+deriving via (GenericallySW (XYZ 'Strong) (XYZ 'Weak)) instance Weaken (XYZ 'Strong)
+deriving via (GenericallySW (XYZ 'Strong) (XYZ 'Weak)) instance Strengthen (XYZ 'Strong)
+@
+
+TODO can't figure out a way around multiple standalone deriving declarations :(
+-}
+
+newtype GenericallySW s (w :: Type) = GenericallySW { unGenericallySW :: s }
+
+instance
+  ( Generic s, Generic w
+  , GWeaken (Rep s) (Rep w)
+  ) => Weaken (GenericallySW s w) where
+    type Weak (GenericallySW s w) = w
+    weaken = weakenGeneric . unGenericallySW
+
+instance
+  ( Generic s, Generic w
+  , GStrengthenD (Rep w) (Rep s)
+  , Weaken (GenericallySW s w)
+  ) => Strengthen (GenericallySW s w) where
+    strengthen = fmap GenericallySW . strengthenGeneric
diff --git a/src/Strongweak/Strengthen.hs b/src/Strongweak/Strengthen.hs
--- a/src/Strongweak/Strengthen.hs
+++ b/src/Strongweak/Strengthen.hs
@@ -40,23 +40,19 @@
 import Data.List.NonEmpty ( NonEmpty( (:|) ) )
 import Data.List.NonEmpty qualified as NonEmpty
 
-{- | You may attempt to transform a @'Weak' a@ to an @a@.
-
-Laws:
-
-  * @a === b -> 'strengthen' a === 'strengthen' b@
-  * @'strengthen' ('weaken' a) === 'Success' a@
+{- | Attempt to strengthen some @'Weak' a@, asserting certain invariants.
 
 We take 'Weaken' as a superclass in order to maintain strong/weak type pair
 consistency. We choose this dependency direction because we treat the strong
 type as the "canonical" one, so 'Weaken' is the more natural (and
-straightforward) class to define.
+straightforward) class to define. That does mean the instances for this class
+are a little confusingly worded. Alas.
 
-Instances should /either/ handle an invariant, or decompose. See "Strongweak"
-for a discussion on this design.
+See "Strongweak" for class design notes and laws.
 -}
 class Weaken a => Strengthen a where
-    -- | Attempt to transform a weak value to its associated strong one.
+    -- | Attempt to strengthen some @'Weak' a@ to its associated strong type
+    --   @a@.
     strengthen :: Weak a -> Validation (NonEmpty StrengthenFail) a
 
 -- | Weaken a strong value, then strengthen it again.
diff --git a/src/Strongweak/Strengthen/Unsafe.hs b/src/Strongweak/Strengthen/Unsafe.hs
--- a/src/Strongweak/Strengthen/Unsafe.hs
+++ b/src/Strongweak/Strengthen/Unsafe.hs
@@ -15,6 +15,9 @@
 
 {- | Unsafely transform a @'Weak' a@ to an @a@, without asserting invariants.
 
+Naturally, you must only even /consider/ using this if you have a guarantee that
+your value is safe to treat as strong.
+
 For example, you may unsafely strengthen some @'Numeric.Natural.Natural' n@ into
 a 'Word8' by unsafely coercing the value, ignoring the possibility that @n >=
 255@.
@@ -24,17 +27,12 @@
 
   * Numeric coercions should safely overflow.
   * Some will raise an error (e.g. 'NonEmpty').
-  * Others will appear to work, but later explode your computer (sized vectors
-    will probably do this).
-
-Only consider using this if you have a guarantee that your value is safe to
-treat as strong.
+  * Others will appear to work, but later explode your computer.
 
-Instances should /either/ handle an invariant, or decompose. See "Strongweak"
-for a discussion on this design.
+See "Strongweak" for class design notes and laws.
 -}
 class Weaken a => UnsafeStrengthen a where
-    -- | Unsafely transform a weak value to its associated strong one.
+    -- | Unsafely transform a @'Weak' a@ to its associated strong type @a@.
     unsafeStrengthen :: Weak a -> a
 
 -- | Add a refinement to a type without checking the associated predicate.
diff --git a/src/Strongweak/Weaken.hs b/src/Strongweak/Weaken.hs
--- a/src/Strongweak/Weaken.hs
+++ b/src/Strongweak/Weaken.hs
@@ -21,26 +21,15 @@
 import Data.List.NonEmpty qualified as NonEmpty
 import Data.List.NonEmpty ( NonEmpty )
 
-{- | Transform an @a@ to a @'Weak' a@.
-
-A given strong type @a@ has exactly one associated weak type @'Weak' a@.
-Multiple strong types may weaken to the same weak type.
-
-The following laws must hold:
-
-  * @a == b |= 'weaken' a == 'weaken' b@
-  * round-trip: @'strengthen' ('weaken' a) == 'pure' a@
+{- | Weaken some @a@, relaxing certain invariants.
 
-Most instances should strip an invariant, and not have a recursive context. Some
-types don't have an invariant
-/either/ handle an invariant, or decompose. See "Strongweak"
-for a discussion on this design.
+See "Strongweak" for class design notes and laws.
 -}
 class Weaken a where
-    -- | The type to weaken to.
+    -- | The weakened type for some type.
     type Weak a :: Type
 
-    -- | Transform a strong value to its associated weak one.
+    -- | Weaken some @a@ to its associated weak type @'Weak' a@.
     weaken :: a -> Weak a
 
 -- | Lift a function on a weak type to the associated strong type.
diff --git a/strongweak.cabal b/strongweak.cabal
--- a/strongweak.cabal
+++ b/strongweak.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           strongweak
-version:        0.4.0
+version:        0.4.1
 synopsis:       Convert between strong and weak representations of types
 description:    Please see README.md.
 category:       Data
@@ -31,6 +31,7 @@
       Strongweak
       Strongweak.Generic
       Strongweak.Generic.Strengthen
+      Strongweak.Generic.Via
       Strongweak.Generic.Weaken
       Strongweak.Strengthen
       Strongweak.Strengthen.Unsafe
