diff --git a/grids.cabal b/grids.cabal
--- a/grids.cabal
+++ b/grids.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 81ed5c93ce5bb167a555fdde42ef9944161ed9cff400c4000736623698c2582f
+-- hash: f761cc1b657f2445a77f2c2026a8f1b6bfae660f46caafca8ac668576cff708a
 
 name:           grids
-version:        0.4.0.0
+version:        0.5.0.0
 description:    Arbitrary sized type-safe grids with useful combinators
 category:       Data Structures
 homepage:       https://github.com/ChrisPenner/grids#readme
@@ -50,7 +50,6 @@
   build-depends:
       adjunctions
     , base >=4.7 && <5
-    , bifunctors
     , comonad
     , deepseq
     , distributive
@@ -72,7 +71,6 @@
   build-depends:
       adjunctions
     , base >=4.7 && <5
-    , bifunctors
     , comonad
     , deepseq
     , distributive
@@ -94,7 +92,6 @@
   build-depends:
       adjunctions
     , base >=4.7 && <5
-    , bifunctors
     , comonad
     , deepseq
     , distributive
diff --git a/src/Data/Grid.hs b/src/Data/Grid.hs
--- a/src/Data/Grid.hs
+++ b/src/Data/Grid.hs
@@ -1,5 +1,7 @@
 module Data.Grid
-  ( Grid(..)
+  (
+   -- * Grids
+  Grid(..)
    -- * Creation
   , generate
   , Rep.tabulate
@@ -39,22 +41,20 @@
    -- * Joining
   , joinGrid
   , splitGrid
-   -- * Assorted
-  , gridSize
    -- * Typeclasses & Type Families
-  , Dimensions
+  , IsGrid
+  , Sizable(..)
   , NestedLists
   , Neighboring
   , ValidPermutation
   , Permuted
   ) where
 
--- * Grids
 import           Data.Grid.Internal.Grid
 import           Data.Grid.Internal.Shapes
-import           Data.Grid.Internal.Nest
 import           Data.Grid.Internal.Lens
 import           Data.Grid.Internal.Transpose
 import           Data.Grid.Internal.Coord
 import           Data.Grid.Internal.Convolution
+import           Data.Grid.Internal.NestedLists
 import           Data.Functor.Rep               as Rep
diff --git a/src/Data/Grid/Examples/Conway.hs b/src/Data/Grid/Examples/Conway.hs
--- a/src/Data/Grid/Examples/Conway.hs
+++ b/src/Data/Grid/Examples/Conway.hs
@@ -10,13 +10,12 @@
 import Data.Functor.Compose
 
 rule' :: Grid [3, 3] Bool -> Bool
-rule' (partitionFocus -> (currentCellAlive,  neighbours)) = (currentCellAlive && livingNeighbours == 2) || livingNeighbours == 3
+rule' (partitionFocus -> (currentCellAlive, neighbours)) =
+  (currentCellAlive && livingNeighbours == 2) || livingNeighbours == 3
   where
     livingNeighbours = length . filter id . toList . Compose $ neighbours
 
-step
-  :: (Dimensions dims)
-  => Grid dims Bool -> Grid dims Bool
+step :: (IsGrid dims) => Grid dims Bool -> Grid dims Bool
 step = autoConvolute @[3, 3] wrapBounds rule'
 
 glider :: [Coord '[10, 10]]
@@ -32,7 +31,5 @@
 showBool True = '#'
 showBool False = '.'
 
-showGrid
-  :: (Dimensions '[x, y])
-  => Grid '[x, y] Bool -> String
+showGrid :: (IsGrid '[x, y]) => Grid '[x, y] Bool -> String
 showGrid = intercalate "\n" . toNestedLists . fmap showBool
diff --git a/src/Data/Grid/Examples/Intro.hs b/src/Data/Grid/Examples/Intro.hs
--- a/src/Data/Grid/Examples/Intro.hs
+++ b/src/Data/Grid/Examples/Intro.hs
@@ -37,13 +37,13 @@
 big :: Grid '[5, 5, 5, 5] Int
 big = generate id
 
-gauss :: (Dimensions dims) => Grid dims Double -> Grid dims Double
+gauss :: (IsGrid dims) => Grid dims Double -> Grid dims Double
 gauss = autoConvolute omitBounds gauss'
  where
   gauss' :: Compose (Grid '[3, 3]) Maybe Double -> Double
   gauss' g = (sum g) / fromIntegral (length g)
 
-clampGauss :: (Dimensions dims) => Grid dims Double -> Grid dims Double
+clampGauss :: (IsGrid dims) => Grid dims Double -> Grid dims Double
 clampGauss = autoConvolute clampBounds gauss'
  where
   gauss' :: Grid '[3, 3] Double -> Double
@@ -65,6 +65,6 @@
 simpleGauss :: Grid '[3, 3] Double
 simpleGauss = gauss doubleGrid
 
-pacmanGauss :: (Dimensions dims) => Grid dims Double -> Grid dims Double
+pacmanGauss :: (IsGrid dims) => Grid dims Double -> Grid dims Double
 pacmanGauss = autoConvolute @'[3, 3] wrapBounds gauss'
   where gauss' g = sum g / fromIntegral (length g)
diff --git a/src/Data/Grid/Internal/Convolution.hs b/src/Data/Grid/Internal/Convolution.hs
--- a/src/Data/Grid/Internal/Convolution.hs
+++ b/src/Data/Grid/Internal/Convolution.hs
@@ -26,8 +26,6 @@
 import           Data.Functor.Rep
 import           Data.Grid.Internal.Coord
 import           Data.Grid.Internal.Grid
-import           Data.Grid.Internal.Nest
-import           GHC.TypeNats
 
 criticalError :: a
 criticalError = error
@@ -53,17 +51,16 @@
 -- repeating values at the edge of the grid when indexes are out of bounds
 -- (using 'clampWindow')
 --
--- > gaussian :: (Dimensions dims) => Grid dims Double -> Grid dims Double
+-- > gaussian :: (IsGrid dims) => Grid dims Double -> Grid dims Double
 -- > gaussian = autoConvolute clampBounds avg
 -- >  where
 -- >   avg :: Grid '[3, 3] Double -> Double
 -- >   avg g = sum g / fromIntegral (length g)
 autoConvolute
   :: forall window dims f a b
-   . ( Dimensions dims
-     , Dimensions window
+   . ( IsGrid dims
+     , IsGrid window
      , Functor f
-     , Neighboring window
      )
   => (Grid window (Coord dims) -> f (Coord dims)) -- ^ Restrict out of bounds coordinates in some way. Use 'clampWindow', 'wrapWindow' or 'safeWindow'
   -> (f a -> b) -- ^ Collapse the context down to a value
@@ -76,7 +73,7 @@
 -- coord, then provides a collapsing function over the same functor.
 convolute
   :: forall dims f a b
-   . (Functor f, Dimensions dims)
+   . (Functor f, IsGrid dims)
   => (Coord dims -> f (Coord dims))  -- ^ Build a neighboring context within a functor from the current coord
   -> (f a -> b) -- ^ Collapse the context to a single value
   -> Grid dims a -- ^ Starting grid
@@ -95,7 +92,7 @@
 -- coordinates surrounding the given coord. Mostly used internally
 window
   :: forall window dims
-   . (Neighboring window, Dimensions window)
+   . (IsGrid window)
   => Coord dims
   -> Grid window (Coord dims)
 window = fromWindow . neighboring . toWindow
@@ -105,40 +102,23 @@
   fromWindow :: Grid window (Coord window) -> Grid window (Coord dims)
   fromWindow = fmap coerceCoordDims
 
-class Neighboring dims where
-  neighborCoords :: Grid dims (Coord dims)
 
-instance {-# OVERLAPPING #-} (KnownNat n) => Neighboring '[n]  where
-  neighborCoords = fromList' . fmap (Coord . pure . subtract (numVals `div` 2)) . take numVals $ [0 .. ]
-    where
-      numVals = gridSize @'[n]
-
-instance (KnownNat n, Neighboring ns) => Neighboring (n:ns) where
-  neighborCoords = joinGrid (addCoord <$> currentLevelNeighbors)
-    where
-      addCoord :: Coord '[n]  -> Grid ns (Coord (n : ns) )
-      addCoord c = appendC c <$> nestedNeighbors
-      nestedNeighbors :: Grid ns (Coord ns )
-      nestedNeighbors = neighborCoords
-      currentLevelNeighbors :: Grid '[n] (Coord '[n] )
-      currentLevelNeighbors = neighborCoords
-
-neighboring :: (Dimensions dims, Neighboring dims) => Coord dims -> Grid dims (Coord dims)
+neighboring :: (IsGrid dims) => Coord dims -> Grid dims (Coord dims)
 neighboring c = (c +) <$> neighborCoords
 
 -- | Use with 'autoConvolute'; Clamp out-of-bounds coordinates to the nearest in-bounds coord.
 clampBounds
-  :: (Dimensions dims, Functor f) => f (Coord dims) -> f (Coord dims)
+  :: (IsGrid dims, Functor f) => f (Coord dims) -> f (Coord dims)
 clampBounds = fmap clampCoord
 
 -- | Use with 'autoConvolute'; Wrap out-of-bounds coordinates pac-man style to the other side of the grid
 wrapBounds
-  :: (Dimensions dims, Functor f) => f (Coord dims) -> f (Coord dims)
+  :: (IsGrid dims, Functor f) => f (Coord dims) -> f (Coord dims)
 wrapBounds = fmap wrapCoord
 
 -- | Use with 'autoConvolute'; Out of bounds coords become 'Nothing'
 omitBounds
-  :: (Dimensions dims, Functor f) => f (Coord dims) -> Compose f Maybe (Coord dims)
+  :: (IsGrid dims, Functor f) => f (Coord dims) -> Compose f Maybe (Coord dims)
 omitBounds = Compose . fmap wrap
   where
     wrap c | coordInBounds c = Just c
diff --git a/src/Data/Grid/Internal/Coord.hs b/src/Data/Grid/Internal/Coord.hs
--- a/src/Data/Grid/Internal/Coord.hs
+++ b/src/Data/Grid/Internal/Coord.hs
@@ -18,10 +18,11 @@
 module Data.Grid.Internal.Coord where
 
 import           GHC.Exts
-import           GHC.TypeNats                      hiding ( Mod )
+import           GHC.TypeNats                   hiding (Mod)
 import           Data.Proxy
 import           Unsafe.Coerce
 import           Data.Singletons.Prelude
+import           Data.Grid.Internal.NestedLists
 
 -- | The index type for 'Grid's.
 newtype Coord (dims :: [Nat]) = Coord {unCoord :: [Int]}
@@ -95,17 +96,11 @@
   toEnum i = Coord [i]
   fromEnum (Coord [i]) = clamp 0 (highestIndex @n) i
 
-instance  (KnownNat x, KnownNat y, SingI rest, Bounded (Coord rest ), Enum (Coord (y:rest) )) => Enum (Coord (x:y:rest) ) where
+instance  (KnownNat x, KnownNat y, Sizable (y:rest), Bounded (Coord rest ), Enum (Coord (y:rest) )) => Enum (Coord (x:y:rest) ) where
   toEnum i | i < 0 = negate $ toEnum (abs i)
   toEnum i | i > fromEnum (maxBound @(Coord (x:y:rest) )) = error "Index out of bounds"
-  toEnum i = (i `div` (gridSize @(y:rest))) :# toEnum (i `mod` gridSize @(y:rest))
-  fromEnum (x :# ys) = (clamp 0 (highestIndex @x) x * gridSize @(y:rest)) + fromEnum ys
-
--- | Get the total size of a 'Grid' of the given dimensions
---
--- > gridSize @'[2, 2] == 4
-gridSize :: forall (dims :: [Nat]) . SingI dims => Int
-gridSize = product . fmap fromIntegral $ demote @dims
+  toEnum i = (i `div` (gridSize $ Proxy @(y:rest))) :# toEnum (i `mod` gridSize (Proxy @(y:rest)))
+  fromEnum (x :# ys) = (clamp 0 (highestIndex @x) x * gridSize (Proxy @(y:rest))) + fromEnum ys
 
 coerceCoordDims :: Coord ns -> Coord ms
 coerceCoordDims = unsafeCoerce
diff --git a/src/Data/Grid/Internal/Grid.hs b/src/Data/Grid/Internal/Grid.hs
--- a/src/Data/Grid/Internal/Grid.hs
+++ b/src/Data/Grid/Internal/Grid.hs
@@ -4,7 +4,7 @@
 
 module Data.Grid.Internal.Grid
   ( Grid(..)
-  , Dimensions(..)
+  , IsGrid
   , Coord
   , NestedLists
   , generate
@@ -14,24 +14,44 @@
   , fromList
   , fromList'
   , (//)
+
+  , Neighboring(..)
+
+  , joinGrid
+  , splitGrid
   )
 where
 
+import Data.Kind
 import           Data.Grid.Internal.NestedLists
 import           Data.Grid.Internal.Coord
 import           Data.Grid.Internal.Pretty
 import           Data.Distributive
 import           Data.Functor.Rep
-import qualified Data.Vector                   as V
+import qualified Data.Vector                    as V
 import           Data.Proxy
-import           GHC.TypeNats                  as N
-                                                   hiding ( Mod )
+import           GHC.TypeNats                   as N hiding (Mod)
 import           Control.Applicative
 import           Data.Bifunctor
 import           Data.Maybe
 import           Data.Singletons.Prelude
 import           Control.DeepSeq
 
+type family AllC (c :: x -> Constraint) (ts :: [x]) :: Constraint where
+  AllC c '[] = ()
+  AllC c (x:xs) = (c x, AllC c xs)
+
+
+type IsGrid dims =
+  ( AllC KnownNat dims
+  , SingI dims
+  , Sizable dims
+  , Representable (Grid dims)
+  , Enum (Coord dims)
+  , Bounded (Coord dims)
+  , Neighboring dims
+  )
+
 -- | An grid of arbitrary dimensions.
 --
 -- e.g. a @Grid [2, 3] Int@ might look like:
@@ -43,28 +63,28 @@
   Grid  {toVector :: V.Vector a}
   deriving (Eq, Functor, Foldable, Traversable, NFData)
 
-instance (PrettyList (NestedLists dims a), Dimensions dims, Show (NestedLists dims a)) => Show (Grid dims a) where
+instance (PrettyList (NestedLists dims a), IsGrid dims, Show (NestedLists dims a)) => Show (Grid dims a) where
   show g = "fromNestedLists \n" ++ (unlines . fmap ("  " ++ ) . lines $ prettyList (toNestedLists g))
 
-instance (Dimensions dims, Semigroup a) => Semigroup (Grid dims a) where
+instance (IsGrid dims, Semigroup a) => Semigroup (Grid dims a) where
   (<>) = liftA2 (<>)
 
-instance (Dimensions dims, Monoid a) => Monoid (Grid dims a) where
+instance (IsGrid dims, Monoid a) => Monoid (Grid dims a) where
   mempty = pure mempty
 
-instance (Dimensions dims) => Applicative (Grid dims) where
+instance (IsGrid dims) => Applicative (Grid dims) where
   pure a = tabulate (const a)
   liftA2 f (Grid v) (Grid u) = Grid $ V.zipWith f v u
 
-instance (Dimensions dims) => Distributive (Grid dims) where
+instance (IsGrid dims) => Distributive (Grid dims) where
   distribute = distributeRep
 
-instance (Dimensions dims) => Representable (Grid dims) where
+instance (IsGrid dims) => Representable (Grid dims) where
   type Rep (Grid dims) = Coord dims
   index (Grid v) c = v V.! fromEnum c
-  tabulate f = Grid $ V.generate (fromIntegral $ gridSize @dims) (f . toEnum  . fromIntegral)
+  tabulate f = Grid $ V.generate (fromIntegral $ gridSize (Proxy @dims)) (f . toEnum  . fromIntegral)
 
-instance (Num n, Dimensions dims) => Num (Grid dims n) where
+instance (Num n, IsGrid dims) => Num (Grid dims n) where
   (+)  = liftA2 (+)
   (*)  = liftA2 (*)
   abs = fmap abs
@@ -73,8 +93,8 @@
   negate = fmap negate
 
 -- | Build a grid by selecting an element for each element
-generate :: forall dims a . (SingI dims) => (Int -> a) -> Grid dims a
-generate f = Grid $ V.generate (gridSize @dims) f
+generate :: forall dims a . (IsGrid dims) => (Int -> a) -> Grid dims a
+generate f = Grid $ V.generate (gridSize $ Proxy @dims) f
 
 -- | Turn a grid into a nested list structure. List nesting increases for each
 -- dimension
@@ -82,7 +102,7 @@
 -- > toNestedLists (G.generate id :: Grid [2, 3] Int)
 -- > [[0,1,2],[3,4,5]]
 toNestedLists
-  :: forall dims a . (Dimensions dims) => Grid dims a -> NestedLists dims a
+  :: forall dims a . (IsGrid dims) => Grid dims a -> NestedLists dims a
 toNestedLists (Grid v) = nestLists (Proxy @dims) v
 
 -- | Turn a nested list structure into a Grid if the list is well formed. 
@@ -94,14 +114,14 @@
 -- > Nothing
 fromNestedLists
   :: forall dims a
-   . Dimensions dims
+   . IsGrid dims
   => NestedLists dims a
   -> Maybe (Grid dims a)
 fromNestedLists = fromList . unNestLists (Proxy @dims)
 
 -- | Partial variant of 'fromNestedLists' which errors on malformed input
 fromNestedLists'
-  :: forall dims a . Dimensions dims => NestedLists dims a -> Grid dims a
+  :: forall dims a . IsGrid dims => NestedLists dims a -> Grid dims a
 fromNestedLists' = fromJust . fromNestedLists
 
 -- | Convert a list into a Grid or fail if not provided the correct number of
@@ -111,20 +131,69 @@
 -- > Just (Grid [[0,1,2],[3,4,5]])
 -- > G.fromList [0, 1, 2, 3] :: Maybe (Grid [2, 3] Int)
 -- > Nothing
-fromList :: forall dims a . (SingI dims) => [a] -> Maybe (Grid dims a)
+fromList :: forall dims a . (IsGrid dims) => [a] -> Maybe (Grid dims a)
 fromList xs =
   let v = V.fromList xs
-  in  if V.length v == gridSize @dims then Just $ Grid v else Nothing
+  in  if V.length v == gridSize (Proxy @dims) then Just $ Grid v else Nothing
 
 -- | Partial variant of 'fromList' which errors on malformed input
-fromList' :: forall dims a . (SingI dims) => [a] -> Grid dims a
+fromList' :: forall dims a . (IsGrid dims) => [a] -> Grid dims a
 fromList' = fromJust . fromList
 
 -- | Update elements of a grid
 (//)
   :: forall dims a
-   . (Enum (Coord dims ))
+   . IsGrid dims
   => Grid dims a
   -> [(Coord dims , a)]
   -> Grid dims a
 (Grid v) // xs = Grid (v V.// fmap (first fromEnum) xs)
+
+class Neighboring dims where
+  neighborCoords :: Grid dims (Coord dims)
+
+
+instance {-# OVERLAPPING #-} (IsGrid '[n]) => Neighboring '[n]  where
+  neighborCoords = fromList' . fmap (Coord . pure . subtract (numVals `div` 2)) . take numVals $ [0 .. ]
+    where
+      numVals = gridSize (Proxy @'[n])
+
+instance (KnownNat n, Neighboring ns) => Neighboring (n:ns) where
+  neighborCoords = joinGrid (addCoord <$> currentLevelNeighbors)
+    where
+      addCoord :: Coord '[n]  -> Grid ns (Coord (n : ns) )
+      addCoord c = appendC c <$> nestedNeighbors
+      nestedNeighbors :: Grid ns (Coord ns )
+      nestedNeighbors = neighborCoords
+      currentLevelNeighbors :: Grid '[n] (Coord '[n] )
+      currentLevelNeighbors = neighborCoords
+
+
+-- | The inverse of 'splitGrid', 
+-- joinGrid will nest a grid from:
+-- > Grid outer (Grid inner a) -> Grid (outer ++ inner) a
+--
+-- For example, you can nest a simple 3x3 from smaller [3] grids as follows:
+--
+-- > joinGrid (myGrid :: Grid [3] (Grid [3] a)) :: Grid '[3, 3] a
+joinGrid :: Grid dims (Grid ns a) -> Grid (dims ++ ns) a
+joinGrid (Grid v) = Grid (v >>= toVector)
+
+-- | The inverse of 'joinGrid', 
+-- splitGrid @outerDims @innerDims will un-nest a grid from:
+-- > Grid (outer ++ inner) a -> Grid outer (Grid inner a)
+--
+-- For example, you can unnest a simple 3x3 as follows:
+--
+-- > splitGrid @'[3] @'[3] myGrid :: Grid '[3] (Grid [3] a)
+splitGrid :: forall outer inner a from.
+          ( IsGrid from
+          , IsGrid inner
+          , IsGrid outer
+          , NestedLists from a ~ NestedLists outer (NestedLists inner a)
+          )
+          => Grid from a
+          -> Grid outer (Grid inner a)
+splitGrid = fmap fromNestedLists' . fromNestedLists' . toNestedLists
+
+
diff --git a/src/Data/Grid/Internal/Lens.hs b/src/Data/Grid/Internal/Lens.hs
--- a/src/Data/Grid/Internal/Lens.hs
+++ b/src/Data/Grid/Internal/Lens.hs
@@ -16,7 +16,7 @@
 -- | Focus an element of a 'Grid' given its 'Coord'
 cell
   :: forall dims a
-   . (Dimensions dims)
+   . (IsGrid dims)
   => Coord dims
   -> Lens' (Grid dims a) a
 cell c = lens get set
diff --git a/src/Data/Grid/Internal/Nest.hs b/src/Data/Grid/Internal/Nest.hs
--- a/src/Data/Grid/Internal/Nest.hs
+++ b/src/Data/Grid/Internal/Nest.hs
@@ -3,36 +3,3 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
 module Data.Grid.Internal.Nest where
-
-import Data.Grid.Internal.Grid
-import Data.Singletons.Prelude
-
-
--- | The inverse of 'splitGrid', 
--- joinGrid will nest a grid from:
--- > Grid outer (Grid inner a) -> Grid (outer ++ inner) a
---
--- For example, you can nest a simple 3x3 from smaller [3] grids as follows:
---
--- > joinGrid (myGrid :: Grid [3] (Grid [3] a)) :: Grid '[3, 3] a
-joinGrid :: Grid dims (Grid ns a) -> Grid (dims ++ ns) a
-joinGrid (Grid v) = Grid (v >>= toVector)
-
--- | The inverse of 'joinGrid', 
--- splitGrid @outerDims @innerDims will un-nest a grid from:
--- > Grid (outer ++ inner) a -> Grid outer (Grid inner a)
---
--- For example, you can unnest a simple 3x3 as follows:
---
--- > splitGrid @'[3] @'[3] myGrid :: Grid '[3] (Grid [3] a)
-splitGrid
-  :: forall outer inner a from
-   . ( from ~ (outer ++ inner)
-     , Dimensions from
-     , Dimensions inner
-     , Dimensions outer
-     , NestedLists from a ~ NestedLists outer (NestedLists inner a)
-     )
-  => Grid from a
-  -> Grid outer (Grid inner a)
-splitGrid = fmap fromNestedLists' . fromNestedLists' . toNestedLists
diff --git a/src/Data/Grid/Internal/NestedLists.hs b/src/Data/Grid/Internal/NestedLists.hs
--- a/src/Data/Grid/Internal/NestedLists.hs
+++ b/src/Data/Grid/Internal/NestedLists.hs
@@ -2,15 +2,9 @@
 {-# LANGUAGE UndecidableSuperClasses #-}
 module Data.Grid.Internal.NestedLists where
 
-import           Data.Kind
-import           GHC.TypeNats                  as N
+import           GHC.TypeNats            as N
 import           Data.Singletons.Prelude
-import qualified Data.Vector                   as V
-import           Data.Grid.Internal.Coord
-
-type family AllC (c :: x -> Constraint) (ts :: [x]) :: Constraint where
-  AllC c '[] = ()
-  AllC c (x:xs) = (c x, AllC c xs)
+import qualified Data.Vector             as V
 
 -- | Computes the level of nesting requried to represent a given grid
 -- dimensionality as a nested list
@@ -31,14 +25,21 @@
 
 -- | Represents valid dimensionalities. All non empty lists of Nats have
 -- an instance
-class (AllC KnownNat dims, SingI dims, Enum (Coord dims), Bounded (Coord dims)) => Dimensions  (dims :: [Nat]) where
+class Sizable  (dims :: [Nat]) where
   nestLists :: Proxy dims -> V.Vector a -> NestedLists dims a
   unNestLists :: Proxy dims -> NestedLists dims a -> [a]
 
-instance (KnownNat x) => Dimensions '[x] where
+  -- | Get the total size of a 'Grid' of the given dimensions
+  --
+  -- > gridSize (Proxy @'[2, 2]) == 4
+  gridSize :: Proxy dims -> Int
+
+instance {-# OVERLAPPING #-} KnownNat x => Sizable '[x] where
   nestLists _ = V.toList
   unNestLists _ xs = xs
+  gridSize _ = fromIntegral $ natVal (Proxy @x)
 
-instance (KnownNat x, Bounded (Coord xs), SingI xs, Dimensions (y:xs)) => Dimensions (x:y:xs) where
-  nestLists _ v = nestLists (Proxy @(y:xs)) <$> chunkVector (gridSize @(y:xs)) v
+instance {-# OVERLAPPABLE #-} (KnownNat x, Sizable (y:xs)) => Sizable (x:y:xs) where
+  nestLists _ v = nestLists (Proxy @(y:xs)) <$> chunkVector (gridSize $ Proxy @(y:xs)) v
   unNestLists _ xs = concat (unNestLists (Proxy @(y:xs)) <$> xs)
+  gridSize _ = gridSize (Proxy @(y:xs)) * fromIntegral (natVal (Proxy @x))
diff --git a/src/Data/Grid/Internal/Shapes.hs b/src/Data/Grid/Internal/Shapes.hs
--- a/src/Data/Grid/Internal/Shapes.hs
+++ b/src/Data/Grid/Internal/Shapes.hs
@@ -22,7 +22,7 @@
 import Data.Grid.Internal.Errors
 
 partitionFocus :: forall window a.
-               (Centered window, Dimensions window)
+               (Centered window, IsGrid window)
                => Grid window a
                -> (a, Grid window (Maybe a))
 partitionFocus g = (g `index` centerCoord @window, imapRep wrapMaybe g)
diff --git a/src/Data/Grid/Internal/Transpose.hs b/src/Data/Grid/Internal/Transpose.hs
--- a/src/Data/Grid/Internal/Transpose.hs
+++ b/src/Data/Grid/Internal/Transpose.hs
@@ -57,8 +57,8 @@
    . ( SingI invertedKey
      , invertedKey ~ InvertKey (EnumFromTo 0 (Length from TL.- 1)) key
      , ValidPermutation key from
-     , Dimensions from 
-     , Dimensions (Permuted key from) 
+     , IsGrid from 
+     , IsGrid (Permuted key from) 
      )
   => Grid from a
   -> Grid (Permuted key from) a
@@ -85,7 +85,7 @@
 -- | Transpose a 2 dimensional matrix. Equivalent to:
 --
 -- > permute @[1, 0]
-transpose :: (KnownNat x, KnownNat y) => Grid '[x, y] a -> Grid '[y, x] a
+transpose :: (IsGrid '[x, y], IsGrid '[y, x]) => Grid '[x, y] a -> Grid '[y, x] a
 transpose = permute @'[1, 0]
 
 -- | Get the inverse of a permutation pattern, used internally
diff --git a/test/Spec/Shapes.hs b/test/Spec/Shapes.hs
--- a/test/Spec/Shapes.hs
+++ b/test/Spec/Shapes.hs
@@ -3,20 +3,12 @@
 module Spec.Shapes (spec) where
 
 import Test.Hspec hiding (focus)
-import qualified Data.Vector as V
 import Data.Grid as G
-import Control.Applicative
-import Data.Maybe
 import Data.Functor.Compose
-import Control.Comonad
 import Control.Monad
-import Data.Coerce
 
 smallGrid :: Grid '[2, 2] Int
 smallGrid = generate id
-
-medGrid :: Grid '[3, 3] Int
-medGrid = generate id
 
 spec :: Spec
 spec = 
