diff --git a/beam.cabal b/beam.cabal
--- a/beam.cabal
+++ b/beam.cabal
@@ -2,7 +2,7 @@
 -- see http://haskell.org/cabal/users-guide/
 
 name:                beam
-version:             0.3.1.0
+version:             0.3.2.0
 synopsis:            A type-safe SQL mapper for Haskell that doesn't use Template Haskell
 description:         See the documentation on [my blog](http://travis.athougies.net/tags/beam.html) and on [GitHub](https://github.com/tathougies/beam/tree/master/Doc).
 homepage:            http://travis.athougies.net/projects/beam.html
diff --git a/src/Database/Beam/Backend/Sqlite3.hs b/src/Database/Beam/Backend/Sqlite3.hs
--- a/src/Database/Beam/Backend/Sqlite3.hs
+++ b/src/Database/Beam/Backend/Sqlite3.hs
@@ -35,5 +35,5 @@
   [res] <- liftIO (quickQuery conn (concat ["SELECT * FROM ", unpack tblName, " WHERE ROWID=(SELECT last_insert_rowid()) limit 1"]) [])
   return res
 
-(++.) :: QExpr Text -> QExpr Text -> QExpr Text
+(++.) :: QExpr s Text -> QExpr s Text -> QExpr s Text
 QExpr a ++. QExpr b = QExpr (SQLBinOpE "||" a b)
diff --git a/src/Database/Beam/Query.hs b/src/Database/Beam/Query.hs
--- a/src/Database/Beam/Query.hs
+++ b/src/Database/Beam/Query.hs
@@ -95,8 +95,8 @@
 insertInto (DatabaseTable _ name) data_ =
     BeamT (\beam -> toBeamResult <$> runInsert name data_ beam)
 
-updateToSQL :: Table table => T.Text -> table QExpr -> QExpr Bool -> Maybe SQLUpdate
-updateToSQL tblName (setTo :: table QExpr) where_ =
+updateToSQL :: Table table => T.Text -> table (QExpr s) -> QExpr s Bool -> Maybe SQLUpdate
+updateToSQL tblName (setTo :: table (QExpr s)) where_ =
     let setExprs = fieldAllValues (\(Columnar' x) -> optimizeExpr x) setTo
         setColumns = fieldAllValues (\(Columnar' fieldS) -> _fieldName fieldS) (tblFieldSettings :: TableSettings table)
 
@@ -119,7 +119,7 @@
 
 -- | Update every entry in the given table where the third argument yields true, using the second
 -- argument to give the new values.
-updateWhere :: (MonadIO m, Table tbl) => DatabaseTable db tbl -> (tbl QExpr -> tbl QExpr) -> (tbl QExpr -> QExpr Bool) -> BeamT e db m ()
+updateWhere :: (MonadIO m, Table tbl) => DatabaseTable db tbl -> (tbl (QExpr s) -> tbl (QExpr s)) -> (tbl (QExpr s) -> QExpr s Bool) -> BeamT e db m ()
 updateWhere tbl@(DatabaseTable _ name :: DatabaseTable db tbl) mkAssignments mkWhere =
     do let assignments = mkAssignments tblExprs
            where_ = mkWhere tblExprs
@@ -142,7 +142,7 @@
     updateWhere tbl (\_ -> tableVal newValues) (val_ (primaryKey newValues) `references_`)
 
 -- | Delete all entries in the given table matched by the expression
-deleteWhere :: (MonadIO m, Table tbl) => DatabaseTable db tbl -> (tbl QExpr -> QExpr Bool) -> BeamT e db m ()
+deleteWhere :: (MonadIO m, Table tbl) => DatabaseTable db tbl -> (tbl (QExpr s) -> QExpr s Bool) -> BeamT e db m ()
 deleteWhere (DatabaseTable _ name :: DatabaseTable db tbl) mkWhere =
     let tblExprs = changeRep (\(Columnar' fieldS) -> Columnar' (QExpr (SQLFieldE (QField name Nothing (_fieldName fieldS))))) (tblFieldSettings :: TableSettings tbl)
 
@@ -180,7 +180,7 @@
             , FromSqlValues (QExprToIdentity a)
             , Projectible a
             , IsQuery q ) =>
-            (forall s. q db s a) -> Beam db m -> m (Either String (Source m (QExprToIdentity a)))
+            q db s a -> Beam db m -> m (Either String (Source m (QExprToIdentity a)))
 runQuery q beam =
     do let selectCmd = Select select
            (_, _, select) = queryToSQL' (toQ q) 0
@@ -202,7 +202,7 @@
 
 -- | Run the given query in the transaction and yield a 'Source' that can be used to read results
 -- incrementally. If your result set is small and you want to just get a list, use 'queryList'.
-query :: (IsQuery q, MonadIO m, Functor m, FromSqlValues (QExprToIdentity a), Projectible a) => (forall s. q db s a) -> BeamT e db m (Source (BeamT e db m) (QExprToIdentity a))
+query :: (IsQuery q, MonadIO m, Functor m, FromSqlValues (QExprToIdentity a), Projectible a) => q db () a -> BeamT e db m (Source (BeamT e db m) (QExprToIdentity a))
 query q = BeamT $ \beam ->
           do res <- runQuery q beam
              case res of
@@ -211,13 +211,13 @@
 
 -- | Execute 'query' and use the 'Data.Conduit.List.consume' function to return a list of
 -- results. Best used for small result sets.
-queryList :: (IsQuery q, MonadIO m, Functor m, FromSqlValues (QExprToIdentity a), Projectible a) => (forall s. q db s a) -> BeamT e db m [QExprToIdentity a]
+queryList :: (IsQuery q, MonadIO m, Functor m, FromSqlValues (QExprToIdentity a), Projectible a) => q db () a -> BeamT e db m [QExprToIdentity a]
 queryList q = do src <- query q
                  src $$ C.consume
 
 -- | Execute the query using 'query' and return exactly one result. The return value will be
 -- 'Nothing' if either zero or more than one values were returned.
-getOne :: (IsQuery q, MonadIO m, Functor m, FromSqlValues (QExprToIdentity a), Projectible a) => (forall s. q db s a) -> BeamT e db m (Maybe (QExprToIdentity a))
+getOne :: (IsQuery q, MonadIO m, Functor m, FromSqlValues (QExprToIdentity a), Projectible a) => q db () a -> BeamT e db m (Maybe (QExprToIdentity a))
 getOne q =
     do let justOneSink = await >>= \x ->
                          case x of
diff --git a/src/Database/Beam/Query/Combinators.hs b/src/Database/Beam/Query/Combinators.hs
--- a/src/Database/Beam/Query/Combinators.hs
+++ b/src/Database/Beam/Query/Combinators.hs
@@ -45,10 +45,10 @@
 import Data.Text (Text)
 import Data.Coerce
 
-instance IsString (QExpr Text) where
+instance IsString (QExpr s Text) where
     fromString = QExpr . SQLValE . SqlString
-instance (Num a, Convertible a SqlValue) => Num (QExpr a) where
-    fromInteger x = let res :: QExpr a
+instance (Num a, Convertible a SqlValue) => Num (QExpr s a) where
+    fromInteger x = let res :: QExpr s a
                         res = val_ (fromInteger x)
                     in res
     QExpr a + QExpr b = QExpr (SQLBinOpE "+" a b)
@@ -57,9 +57,9 @@
     negate (QExpr a) = QExpr (SQLUnOpE "-" a)
     abs (QExpr x) = QExpr (SQLFuncE "ABS" [x])
     signum x = error "signum: not defined for QExpr. Use CASE...WHEN"
-instance IsString (Aggregation Text) where
+instance IsString (Aggregation s Text) where
     fromString = ProjectAgg . SQLValE . SqlString
-instance (Num a, Convertible a SqlValue) => Num (Aggregation a) where
+instance (Num a, Convertible a SqlValue) => Num (Aggregation s a) where
     fromInteger x = ProjectAgg (SQLValE (convert (fromInteger x :: a)))
     ProjectAgg a + ProjectAgg b = ProjectAgg (SQLBinOpE "+" a b)
     ProjectAgg a - ProjectAgg b = ProjectAgg (SQLBinOpE "-" a b)
@@ -69,19 +69,19 @@
     signum x = error "signum: not defined for Aggregation. Use CASE...WHEN"
 
 -- | Introduce all entries of a table into the 'Q' monad
-all_ :: Database db => DatabaseTable db table -> Q db s (table QExpr)
+all_ :: Database db => DatabaseTable db table -> Q db s (table (QExpr s))
 all_ tbl = join_ tbl (val_ True)
 
 -- | Introduce all entries of a table into the 'Q' monad based on the given SQLExpr
-join_ :: Database db => DatabaseTable db table -> QExpr Bool -> Q db s (table QExpr)
-join_ (DatabaseTable table name :: DatabaseTable db table) on =
+join_ :: Database db => DatabaseTable db table -> QExpr s Bool -> Q db s (table (QExpr s))
+join_ (DatabaseTable table name :: DatabaseTable db table) (QExpr on) =
     do curTbl <- gets qbNextTblRef
        modify $ \qb@QueryBuilder { qbNextTblRef = curTbl
                                  , qbFrom = from
                                  , qbWhere = where_ } ->
            let (from', where') = case from of
-                                   Nothing -> (Just newSource, where_ &&. on)
-                                   Just from -> ( Just (SQLJoin SQLInnerJoin from newSource (optimizeExpr on)),
+                                   Nothing -> (Just newSource, SQLBinOpE "AND" where_ on)
+                                   Just from -> ( Just (SQLJoin SQLInnerJoin from newSource (optimizeExpr' on)),
                                                   where_ )
                newSource = SQLFromSource (SQLAliased (SQLSourceTable name) (Just (fromString ("t" <> show curTbl))))
            in qb { qbNextTblRef = curTbl + 1
@@ -91,14 +91,14 @@
        let tableSettings :: TableSettings table
            tableSettings = tblFieldSettings
 
-           mkScopedField :: Columnar' (TableField table) a -> Columnar' QExpr a
+           mkScopedField :: Columnar' (TableField table) a -> Columnar' (QExpr s) a
            mkScopedField (Columnar' f) = Columnar' (QExpr (SQLFieldE (QField name (Just curTbl) (_fieldName f))))
        pure (changeRep mkScopedField tableSettings)
 
 -- | Introduce a table using a left join. Because this is not an inner join, the resulting table is
 -- made nullable. This means that each field that would normally have type 'QExpr x' will now have
 -- type 'QExpr (Maybe x)'.
-leftJoin_ :: Database db => DatabaseTable db table -> QExpr Bool -> Q db s (table (Nullable QExpr))
+leftJoin_ :: Database db => DatabaseTable db table -> QExpr s Bool -> Q db s (table (Nullable (QExpr s)))
 leftJoin_ (DatabaseTable table name :: DatabaseTable db table) on =
     do curTbl <- gets qbNextTblRef
        modify $ \qb@QueryBuilder { qbNextTblRef = curTbl
@@ -113,44 +113,44 @@
        let tableSettings :: TableSettings table
            tableSettings = tblFieldSettings
 
-           mkScopedField :: Columnar' (TableField table) a -> Columnar' (Nullable QExpr) a
+           mkScopedField :: Columnar' (TableField table) a -> Columnar' (Nullable (QExpr s)) a
            mkScopedField (Columnar' f) = Columnar' (QExpr (SQLFieldE (QField name (Just curTbl) (_fieldName f))))
        pure (changeRep mkScopedField tableSettings)
 
 -- | Only allow results for which the 'QExpr' yields 'True'
-guard_ :: QExpr Bool -> Q db s ()
-guard_ guardE' = modify $ \qb@QueryBuilder { qbWhere = guardE } -> qb { qbWhere = guardE &&. guardE' }
+guard_ :: QExpr s Bool -> Q db s ()
+guard_ (QExpr guardE') = modify $ \qb@QueryBuilder { qbWhere = guardE } -> qb { qbWhere = SQLBinOpE "AND" guardE guardE' }
 
 -- | Introduce all entries of the given table which are referenced by the given 'PrimaryKey'
-related_ :: (Database db, Table rel) => DatabaseTable db rel -> PrimaryKey rel QExpr -> Q db s (rel QExpr)
+related_ :: (Database db, Table rel) => DatabaseTable db rel -> PrimaryKey rel (QExpr s) -> Q db s (rel (QExpr s))
 related_ (relTbl :: DatabaseTable db rel) pk =
     mdo rel <- join_ relTbl (pk ==. primaryKey rel)
         pure rel
 
 -- | Introduce all entries of the given table which for which the expression (which can depend on the queried table returns true)
-relatedBy_ :: (Database db, Table rel) => DatabaseTable db rel -> (rel QExpr -> QExpr Bool) -> Q db s (rel QExpr)
+relatedBy_ :: (Database db, Table rel) => DatabaseTable db rel -> (rel (QExpr s) -> QExpr s Bool) -> Q db s (rel (QExpr s))
 relatedBy_ (relTbl :: DatabaseTable db rel) mkOn =
     mdo rel <- join_ relTbl (mkOn rel)
         pure rel
 
 -- | Introduce related entries of the given table, or if no related entries exist, introduce the null table
-perhapsAll_ :: (Database db, Table rel) => DatabaseTable db rel -> (rel (Nullable QExpr) -> QExpr Bool) -> Q db s (rel (Nullable QExpr))
+perhapsAll_ :: (Database db, Table rel) => DatabaseTable db rel -> (rel (Nullable (QExpr s)) -> QExpr s Bool) -> Q db s (rel (Nullable (QExpr s)))
 perhapsAll_ relTbl expr =
     mdo rel <- leftJoin_ relTbl (expr rel)
         pure rel
 
 -- | Synonym for 'related_'
-lookup_ :: (Database db, Table rel) => DatabaseTable db rel -> PrimaryKey rel QExpr -> Q db s (rel QExpr)
+lookup_ :: (Database db, Table rel) => DatabaseTable db rel -> PrimaryKey rel (QExpr s) -> Q db s (rel (QExpr s))
 lookup_ = related_
 
-class SqlReferences f where
+class SqlReferences f s where
     -- | Check that the 'PrimaryKey' given matches the table. Polymorphic so it works over both
     -- regular tables and those that have been made nullable by 'leftJoin_'.
-    references_ :: Table tbl => PrimaryKey tbl f -> tbl f -> QExpr Bool
-instance SqlReferences QExpr where
-    references_ pk (tbl :: tbl QExpr) = pk ==. primaryKey tbl
-instance SqlReferences (Nullable QExpr) where
-    references_ pk (tbl :: tbl (Nullable QExpr)) = pk ==. primaryKey tbl
+    references_ :: Table tbl => PrimaryKey tbl f -> tbl f -> QExpr s Bool
+instance SqlReferences (QExpr s) s where
+    references_ pk (tbl :: tbl (QExpr s)) = pk ==. primaryKey tbl
+instance SqlReferences (Nullable (QExpr s)) s where
+    references_ pk (tbl :: tbl (Nullable (QExpr s))) = pk ==. primaryKey tbl
 
 -- | Limit the number of results returned by a query.
 --
@@ -181,45 +181,45 @@
        pure res
 
 -- | Use the SQL exists operator to determine if the given query returns any results
-exists_ :: (IsQuery q, Projectible a) => q db s a -> QExpr Bool
+exists_ :: (IsQuery q, Projectible a) => q db s a -> QExpr s Bool
 exists_ q = let (_, _, selectCmd) = queryToSQL' (toQ q) 0
             in QExpr (SQLExistsE selectCmd)
 
 -- ** Combinators for boolean expressions
 
-class SqlOrd a where
-    (==.), (/=.) :: a -> a -> QExpr Bool
+class SqlOrd a s where
+    (==.), (/=.) :: a -> a -> QExpr s Bool
     a /=. b = not_ (a ==. b)
 
-instance SqlOrd (QExpr a) where
+instance SqlOrd (QExpr s a) s where
     (==.) = binOpE "=="
     (/=.) = binOpE "<>"
 
-newtype QExprBool a = QExprBool (QExpr Bool)
+newtype QExprBool s a = QExprBool (QExpr s Bool)
 
-instance {-# OVERLAPPING #-} Table tbl => SqlOrd (PrimaryKey tbl QExpr) where
-    a ==. b = let pkCmp = runIdentity (zipPkM (\(Columnar' x) (Columnar' y) -> return (Columnar' (QExprBool (x ==. y))) ) a b) :: PrimaryKey tbl QExprBool
+instance {-# OVERLAPPING #-} Table tbl => SqlOrd (PrimaryKey tbl (QExpr s)) s where
+    a ==. b = let pkCmp = runIdentity (zipPkM (\(Columnar' x) (Columnar' y) -> return (Columnar' (QExprBool (x ==. y))) ) a b) :: PrimaryKey tbl (QExprBool s)
               in foldr (&&.) (val_ True) (pkAllValues (\(Columnar' (QExprBool x)) -> x) pkCmp)
-instance {-# OVERLAPPING #-} Table tbl => SqlOrd (tbl QExpr) where
-    a ==. b = let tblCmp = runIdentity (zipTablesM (\(Columnar' x) (Columnar' y) -> return (Columnar' (QExprBool (x ==. y))) ) a b) :: tbl QExprBool
+instance {-# OVERLAPPING #-} Table tbl => SqlOrd (tbl (QExpr s)) s where
+    a ==. b = let tblCmp = runIdentity (zipTablesM (\(Columnar' x) (Columnar' y) -> return (Columnar' (QExprBool (x ==. y))) ) a b) :: tbl (QExprBool s)
               in foldr (&&.) (val_ True) (fieldAllValues (\(Columnar' (QExprBool x)) -> x) tblCmp)
 
-instance {-# OVERLAPPING #-} Table tbl => SqlOrd (PrimaryKey tbl (Nullable QExpr)) where
-    a ==. b = let pkCmp = runIdentity (zipPkM (\(Columnar' x) (Columnar' y) -> return (Columnar' (QExprBool (x ==. y))) ) a b) :: PrimaryKey tbl QExprBool
+instance {-# OVERLAPPING #-} Table tbl => SqlOrd (PrimaryKey tbl (Nullable (QExpr s))) s where
+    a ==. b = let pkCmp = runIdentity (zipPkM (\(Columnar' x) (Columnar' y) -> return (Columnar' (QExprBool (x ==. y))) ) a b) :: PrimaryKey tbl (QExprBool s)
               in foldr (&&.) (val_ True) (pkAllValues (\(Columnar' (QExprBool x)) -> x) pkCmp)
-instance {-# OVERLAPPING #-} Table tbl => SqlOrd (tbl (Nullable QExpr)) where
-    a ==. b = let tblCmp = runIdentity (zipTablesM (\(Columnar' x) (Columnar' y) -> return (Columnar' (QExprBool (x ==. y))) ) a b) :: tbl QExprBool
+instance {-# OVERLAPPING #-} Table tbl => SqlOrd (tbl (Nullable (QExpr s))) s where
+    a ==. b = let tblCmp = runIdentity (zipTablesM (\(Columnar' x) (Columnar' y) -> return (Columnar' (QExprBool (x ==. y))) ) a b) :: tbl (QExprBool s)
               in foldr (&&.) (val_ True) (fieldAllValues (\(Columnar' (QExprBool x)) -> x) tblCmp)
 
 binOpE op (QExpr a) (QExpr b) = QExpr (SQLBinOpE op a b)
 
-(<.), (>.), (<=.), (>=.) :: QExpr a -> QExpr a -> QExpr Bool
+(<.), (>.), (<=.), (>=.) :: QExpr s a -> QExpr s a -> QExpr s Bool
 (<.) = binOpE "<"
 (>.) = binOpE ">"
 (<=.) = binOpE "<="
 (>=.) = binOpE ">="
 
-(&&.), (||.) :: QExpr Bool -> QExpr Bool -> QExpr Bool
+(&&.), (||.) :: QExpr s Bool -> QExpr s Bool -> QExpr s Bool
 (&&.) = binOpE "AND"
 (||.) = binOpE "OR"
 
@@ -227,81 +227,81 @@
 infixr 2 ||.
 infix 4 ==., /=.
 
-not_ :: QExpr Bool -> QExpr Bool
+not_ :: QExpr s Bool -> QExpr s Bool
 not_ (QExpr a) = QExpr (SQLUnOpE "NOT" a)
 
-mod_, div_ :: Integral a => QExpr a -> QExpr a -> QExpr a
+mod_, div_ :: Integral a => QExpr s a -> QExpr s a -> QExpr s a
 div_ = binOpE "/"
 mod_ = binOpE "%"
 
 -- * Marshalling between Haskell literals and QExprs
 
 type family HaskellLiteralForQExpr x
-type instance HaskellLiteralForQExpr (QExpr a) = a
-type instance HaskellLiteralForQExpr (table QExpr) = table Identity
+type instance HaskellLiteralForQExpr (QExpr s a) = a
+type instance HaskellLiteralForQExpr (table (QExpr s)) = table Identity
 
 class SqlValable a where
     val_ :: HaskellLiteralForQExpr a -> a
-instance Convertible a SqlValue => SqlValable (QExpr a) where
+instance Convertible a SqlValue => SqlValable (QExpr s a) where
     val_ = QExpr . SQLValE . convert
 
 -- NOTE: This shouldn't cause problems because both overlapping instances are in the same module.
 --       GHC should prefer the PrimaryKey one for primary keys and the table one for everything else.
 --       AFAICT, PrimaryKey tbl QExpr ~ tbl QExpr is impossible
-instance {-# OVERLAPPING #-} Table tbl => SqlValable (PrimaryKey tbl QExpr) where
+instance {-# OVERLAPPING #-} Table tbl => SqlValable (PrimaryKey tbl (QExpr s)) where
     val_ = pkChangeRep valToQExpr . pkMakeSqlValues
-        where valToQExpr :: Columnar' SqlValue' a -> Columnar' QExpr a
+        where valToQExpr :: Columnar' SqlValue' a -> Columnar' (QExpr s) a
               valToQExpr (Columnar' (SqlValue' v)) = Columnar' (QExpr (SQLValE v))
-instance {-# OVERLAPPING #-} Table tbl => SqlValable (tbl QExpr) where
+instance {-# OVERLAPPING #-} Table tbl => SqlValable (tbl (QExpr s)) where
     val_ = changeRep valToQExpr . makeSqlValues
-        where valToQExpr :: Columnar' SqlValue' a -> Columnar' QExpr a
+        where valToQExpr :: Columnar' SqlValue' a -> Columnar' (QExpr s) a
               valToQExpr (Columnar' (SqlValue' v)) = Columnar' (QExpr (SQLValE v))
 
 -- * Aggregators
 
-class Aggregating agg where
-    type LiftAggregationsToQExpr agg
+class Aggregating agg s | agg -> s where
+    type LiftAggregationsToQExpr agg s
 
-    aggToSql :: agg -> SQLGrouping
-    liftAggToQExpr :: agg -> LiftAggregationsToQExpr agg
-instance Table t => Aggregating (t Aggregation) where
-    type LiftAggregationsToQExpr (t Aggregation) = t QExpr
-    aggToSql table = mconcat (fieldAllValues (\(Columnar' x) -> aggToSql x) table)
-    liftAggToQExpr = changeRep (\(Columnar' x) -> Columnar' (liftAggToQExpr x))
-instance Aggregating (Aggregation a) where
-    type LiftAggregationsToQExpr (Aggregation a) = QExpr a
-    aggToSql (GroupAgg e) = let eSql = optimizeExpr' e
-                            in mempty { sqlGroupBy = [eSql] }
-    aggToSql (ProjectAgg _) = mempty
+    aggToSql :: Proxy s -> agg -> SQLGrouping
+    liftAggToQExpr :: Proxy s -> agg -> LiftAggregationsToQExpr agg s
+instance Table t => Aggregating (t (Aggregation s)) s where
+    type LiftAggregationsToQExpr (t (Aggregation s)) s = t (QExpr s)
+    aggToSql s table = mconcat (fieldAllValues (\(Columnar' x) -> aggToSql s x) table)
+    liftAggToQExpr s = changeRep (\(Columnar' x) -> Columnar' (liftAggToQExpr s x))
+instance Aggregating (Aggregation s a) s where
+    type LiftAggregationsToQExpr (Aggregation s a) s = QExpr s a
+    aggToSql _ (GroupAgg e) = let eSql = optimizeExpr' e
+                              in mempty { sqlGroupBy = [eSql] }
+    aggToSql _ (ProjectAgg _) = mempty
 
-    liftAggToQExpr (GroupAgg e) = QExpr e
-    liftAggToQExpr (ProjectAgg e) = QExpr e
-instance (Aggregating a, Aggregating b) => Aggregating (a, b) where
-    type LiftAggregationsToQExpr (a, b) = ( LiftAggregationsToQExpr a
-                                          , LiftAggregationsToQExpr b )
-    aggToSql (a, b) = aggToSql a <> aggToSql b
-    liftAggToQExpr (a, b) = (liftAggToQExpr a, liftAggToQExpr b)
-instance (Aggregating a, Aggregating b, Aggregating c) => Aggregating (a, b, c) where
-    type LiftAggregationsToQExpr (a, b, c) = ( LiftAggregationsToQExpr a
-                                             , LiftAggregationsToQExpr b
-                                             , LiftAggregationsToQExpr c )
-    aggToSql (a, b, c) = aggToSql a <> aggToSql b <> aggToSql c
-    liftAggToQExpr (a, b, c) = (liftAggToQExpr a, liftAggToQExpr b, liftAggToQExpr c)
-instance (Aggregating a, Aggregating b, Aggregating c, Aggregating d) => Aggregating (a, b, c, d) where
-    type LiftAggregationsToQExpr (a, b, c, d) = ( LiftAggregationsToQExpr a
-                                                , LiftAggregationsToQExpr b
-                                                , LiftAggregationsToQExpr c
-                                                , LiftAggregationsToQExpr d )
-    aggToSql (a, b, c, d) = aggToSql a <> aggToSql b <> aggToSql c <> aggToSql d
-    liftAggToQExpr (a, b, c, d) = (liftAggToQExpr a, liftAggToQExpr b, liftAggToQExpr c, liftAggToQExpr d)
-instance (Aggregating a, Aggregating b, Aggregating c, Aggregating d, Aggregating e) => Aggregating (a, b, c, d, e) where
-    type LiftAggregationsToQExpr (a, b, c, d, e) = ( LiftAggregationsToQExpr a
-                                                   , LiftAggregationsToQExpr b
-                                                   , LiftAggregationsToQExpr c
-                                                   , LiftAggregationsToQExpr d
-                                                   , LiftAggregationsToQExpr e )
-    aggToSql (a, b, c, d, e) = aggToSql a <> aggToSql b <> aggToSql c <> aggToSql d <> aggToSql e
-    liftAggToQExpr (a, b, c, d, e) = (liftAggToQExpr a, liftAggToQExpr b, liftAggToQExpr c, liftAggToQExpr d, liftAggToQExpr e)
+    liftAggToQExpr _ (GroupAgg e) = QExpr e
+    liftAggToQExpr _ (ProjectAgg e) = QExpr e
+instance (Aggregating a s, Aggregating b s) => Aggregating (a, b) s where
+    type LiftAggregationsToQExpr (a, b) s = ( LiftAggregationsToQExpr a s
+                                            , LiftAggregationsToQExpr b s)
+    aggToSql s (a, b) = aggToSql s a <> aggToSql s b
+    liftAggToQExpr s (a, b) = (liftAggToQExpr s a, liftAggToQExpr s b)
+instance (Aggregating a s, Aggregating b s, Aggregating c s) => Aggregating (a, b, c) s where
+    type LiftAggregationsToQExpr (a, b, c) s = ( LiftAggregationsToQExpr a s
+                                               , LiftAggregationsToQExpr b s
+                                               , LiftAggregationsToQExpr c s )
+    aggToSql s (a, b, c) = aggToSql s a <> aggToSql s b <> aggToSql s c
+    liftAggToQExpr s (a, b, c) = (liftAggToQExpr s a, liftAggToQExpr s b, liftAggToQExpr s c)
+instance (Aggregating a s, Aggregating b s, Aggregating c s, Aggregating d s) => Aggregating (a, b, c, d) s where
+    type LiftAggregationsToQExpr (a, b, c, d) s = ( LiftAggregationsToQExpr a s
+                                                  , LiftAggregationsToQExpr b s
+                                                  , LiftAggregationsToQExpr c s
+                                                  , LiftAggregationsToQExpr d s)
+    aggToSql s (a, b, c, d) = aggToSql s a <> aggToSql s b <> aggToSql s c <> aggToSql s d
+    liftAggToQExpr s (a, b, c, d) = (liftAggToQExpr s a, liftAggToQExpr s b, liftAggToQExpr s c, liftAggToQExpr s d)
+instance (Aggregating a s, Aggregating b s, Aggregating c s, Aggregating d s, Aggregating e s) => Aggregating (a, b, c, d, e) s where
+    type LiftAggregationsToQExpr (a, b, c, d, e) s = ( LiftAggregationsToQExpr a s
+                                                     , LiftAggregationsToQExpr b s
+                                                     , LiftAggregationsToQExpr c s
+                                                     , LiftAggregationsToQExpr d s
+                                                     , LiftAggregationsToQExpr e s)
+    aggToSql s (a, b, c, d, e) = aggToSql s a <> aggToSql s b <> aggToSql s c <> aggToSql s d <> aggToSql s e
+    liftAggToQExpr s (a, b, c, d, e) = (liftAggToQExpr s a, liftAggToQExpr s b, liftAggToQExpr s c, liftAggToQExpr s d, liftAggToQExpr s e)
 
 -- | Type class for things that can be used as the basis of a grouping in a SQL GROUP BY
 -- clause. This includes 'QExpr a', 'Table's, and 'PrimaryKey's. Because the given object forms the
@@ -312,20 +312,20 @@
     -- | When included in an 'Aggregating' expression, causes the results to be grouped by the
     -- given column.
     group_ :: a -> GroupResult a
-instance SqlGroupable (QExpr a) where
-    type GroupResult (QExpr a) = Aggregation a
+instance SqlGroupable (QExpr s a) where
+    type GroupResult (QExpr s a) = Aggregation s a
     group_ (QExpr a) = GroupAgg a
-instance {-# OVERLAPPING #-} Table t => SqlGroupable (PrimaryKey t QExpr) where
-    type GroupResult (PrimaryKey t QExpr) = PrimaryKey t Aggregation
+instance {-# OVERLAPPING #-} Table t => SqlGroupable (PrimaryKey t (QExpr s)) where
+    type GroupResult (PrimaryKey t (QExpr s)) = PrimaryKey t (Aggregation s)
     group_ = pkChangeRep (\(Columnar' (QExpr e)) -> Columnar' (GroupAgg e))
-instance {-# OVERLAPPING #-} Table t => SqlGroupable (t QExpr) where
-    type GroupResult (t QExpr) = t Aggregation
+instance {-# OVERLAPPING #-} Table t => SqlGroupable (t (QExpr s)) where
+    type GroupResult (t (QExpr s)) = t (Aggregation s)
     group_ = changeRep (\(Columnar' (QExpr e)) -> Columnar' (GroupAgg e))
 
-sum_ :: Num a => QExpr a -> Aggregation a
+sum_ :: Num a => QExpr s a -> Aggregation s a
 sum_ (QExpr over) = ProjectAgg (SQLFuncE "SUM" [over])
 
-count_ :: QExpr a -> Aggregation Int
+count_ :: QExpr s a -> Aggregation s Int
 count_ (QExpr over) = ProjectAgg (SQLFuncE "COUNT" [over])
 
 -- | Return a 'TopLevelQ' that will aggregate over the results of the original query. The
@@ -339,20 +339,20 @@
 --
 -- will group the result of the `all_ employeesTable` query using the `_employeeRegion` record
 -- field, and then count up the number of employees for each region.
-aggregate :: (Projectible a, Aggregating agg) => (a -> agg) -> (forall s. Q db s a) -> TopLevelQ db s (LiftAggregationsToQExpr agg)
-aggregate aggregator q =
+aggregate :: (Projectible a, Aggregating agg s) => (a -> agg) -> Q db s a -> TopLevelQ db s (LiftAggregationsToQExpr agg s)
+aggregate (aggregator :: a -> agg) (q :: Q db s a) =
     TopLevelQ $
     do res <- q
 
        curTbl <- gets qbNextTblRef
        let aggregation = aggregator res
-           grouping' = aggToSql aggregation
+           grouping' = aggToSql (Proxy :: Proxy s) aggregation
        modify $ \qb -> case sqlGroupBy grouping' of
                          [] -> qb
                          _ -> case qbGrouping qb of
                                 Nothing -> qb { qbGrouping = Just grouping' }
                                 Just grouping -> qb { qbGrouping = Just (grouping <> grouping') }
-       pure (liftAggToQExpr aggregation)
+       pure (liftAggToQExpr (Proxy :: Proxy s) aggregation)
 
 -- * Order bys
 
@@ -390,79 +390,86 @@
        modify $ \qb -> qb { qbOrdering = qbOrdering qb <> ordering }
        pure res
 
-desc_, asc_ :: QExpr a -> SQLOrdering
+desc_, asc_ :: QExpr s a -> SQLOrdering
 asc_ e = Asc (optimizeExpr e)
 desc_ e = Desc (optimizeExpr e)
 
 -- * Subqueries
 
-class Subqueryable a where
-    subqueryProjections :: a -> RWS (Text, Int) [SQLAliased SQLExpr] Int a
-instance Subqueryable (QExpr a) where
-    subqueryProjections e =
+class Subqueryable a s | a -> s where
+    type Unnested a s
+    subqueryProjections :: Proxy s -> a -> RWS (Text, Int) [SQLAliased SQLExpr] Int (Unnested a s)
+instance Subqueryable (QExpr (QNested s) a) s where
+    type Unnested (QExpr (QNested s) a) s = QExpr s a
+    subqueryProjections s e =
         do i <- state (\i -> (i, i+1))
            (tblName, tblOrd) <- ask
            let fieldName = fromString ("e" <> show i)
            tell [SQLAliased (optimizeExpr e) (Just fieldName)]
            pure (QExpr (SQLFieldE (QField tblName (Just tblOrd) fieldName)))
-instance ( Subqueryable a
-         , Subqueryable b ) =>
-    Subqueryable (a, b) where
-    subqueryProjections (a, b) =
-        (,) <$> subqueryProjections a
-            <*> subqueryProjections b
-instance ( Subqueryable a
-         , Subqueryable b
-         , Subqueryable c ) =>
-    Subqueryable (a, b, c) where
-    subqueryProjections (a, b, c) =
-        (,,) <$> subqueryProjections a
-             <*> subqueryProjections b
-             <*> subqueryProjections c
-instance ( Subqueryable a
-         , Subqueryable b
-         , Subqueryable c
-         , Subqueryable d ) =>
-    Subqueryable (a, b, c, d) where
-    subqueryProjections (a, b, c, d) =
-        (,,,) <$> subqueryProjections a
-              <*> subqueryProjections b
-              <*> subqueryProjections c
-              <*> subqueryProjections d
-instance ( Subqueryable a
-         , Subqueryable b
-         , Subqueryable c
-         , Subqueryable d
-         , Subqueryable e ) =>
-    Subqueryable (a, b, c, d, e) where
-    subqueryProjections (a, b, c, d, e) =
-        (,,,,) <$> subqueryProjections a
-               <*> subqueryProjections b
-               <*> subqueryProjections c
-               <*> subqueryProjections d
-               <*> subqueryProjections e
+instance ( Subqueryable a s
+         , Subqueryable b s ) =>
+    Subqueryable (a, b) s where
+    type Unnested (a, b) s = (Unnested a s, Unnested b s)
+    subqueryProjections s (a, b) =
+        (,) <$> subqueryProjections s a
+            <*> subqueryProjections s b
+instance ( Subqueryable a s
+         , Subqueryable b s
+         , Subqueryable c s ) =>
+    Subqueryable (a, b, c) s where
+    type Unnested (a, b, c) s = (Unnested a s, Unnested b s, Unnested c s)
+    subqueryProjections s (a, b, c) =
+        (,,) <$> subqueryProjections s a
+             <*> subqueryProjections s b
+             <*> subqueryProjections s c
+instance ( Subqueryable a s
+         , Subqueryable b s
+         , Subqueryable c s
+         , Subqueryable d s ) =>
+    Subqueryable (a, b, c, d) s where
+    type Unnested (a, b, c, d) s = (Unnested a s, Unnested b s, Unnested c s, Unnested d s)
+    subqueryProjections s (a, b, c, d) =
+        (,,,) <$> subqueryProjections s a
+              <*> subqueryProjections s b
+              <*> subqueryProjections s c
+              <*> subqueryProjections s d
+instance ( Subqueryable a s
+         , Subqueryable b s
+         , Subqueryable c s
+         , Subqueryable d s
+         , Subqueryable e s ) =>
+    Subqueryable (a, b, c, d, e) s where
+    type Unnested (a, b, c, d, e) s = (Unnested a s, Unnested b s, Unnested c s, Unnested d s, Unnested e s)
+    subqueryProjections s (a, b, c, d, e) =
+        (,,,,) <$> subqueryProjections s a
+               <*> subqueryProjections s b
+               <*> subqueryProjections s c
+               <*> subqueryProjections s d
+               <*> subqueryProjections s e
 
 -- | Run the given 'Q'-like object as a subquery, joining the results with the current result
 -- set. This allows embedding of 'TopLevelQ's inside 'Q's or other 'TopLevelQ's.
-subquery_ :: (IsQuery q, Projectible a, Subqueryable a) => (forall s. q db s a) -> Q db s a
-subquery_ q = do curTbl <- gets qbNextTblRef
+subquery_ :: (IsQuery q, Projectible a, Subqueryable a s) => q db (QNested s) a -> Q db s (Unnested a s)
+subquery_ (q :: q db (QNested s) a) =
+    do curTbl <- gets qbNextTblRef
 
-                 let (res, curTbl', select') = queryToSQL' (toQ q) curTbl
+       let (res, curTbl', select') = queryToSQL' (toQ q) curTbl
 
-                     subTblName = fromString ("t" <> show curTbl)
-                     (res', projection') = evalRWS (subqueryProjections res) (subTblName, curTbl') 0
+           subTblName = fromString ("t" <> show curTbl)
+           (res', projection') = evalRWS (subqueryProjections (Proxy :: Proxy s) res) (subTblName, curTbl') 0
 
-                     select'' = select' { selProjection = SQLProj projection' }
+           select'' = select' { selProjection = SQLProj projection' }
 
-                 modify $ \qb@QueryBuilder { qbFrom = from } ->
-                           let from' = case from of
-                                         Nothing -> Just newSource
-                                         Just from -> Just (SQLJoin SQLInnerJoin from newSource (SQLValE (SqlBool True)))
-                               newSource = SQLFromSource (SQLAliased (SQLSourceSelect select'') (Just (fromString ("t" <> show curTbl'))))
-                           in qb { qbNextTblRef = curTbl' + 1
-                                 , qbFrom = from' }
+       modify $ \qb@QueryBuilder { qbFrom = from } ->
+                 let from' = case from of
+                               Nothing -> Just newSource
+                               Just from -> Just (SQLJoin SQLInnerJoin from newSource (SQLValE (SqlBool True)))
+                     newSource = SQLFromSource (SQLAliased (SQLSourceSelect select'') (Just (fromString ("t" <> show curTbl'))))
+                 in qb { qbNextTblRef = curTbl' + 1
+                       , qbFrom = from' }
 
-                 pure res'
+       pure res'
 
 -- * Nullable conversions
 
@@ -479,15 +486,15 @@
     -- 'PrimaryKey' filled with 'Nothing'.
     nothing_ :: b
 
-instance SqlJustable (QExpr a) (QExpr (Maybe a)) where
+instance SqlJustable (QExpr s a) (QExpr s (Maybe a)) where
     just_ (QExpr e) = QExpr e
     nothing_ = QExpr (SQLValE SqlNull)
 
-instance {-# OVERLAPPING #-} Table t => SqlJustable (PrimaryKey t QExpr) (PrimaryKey t (Nullable QExpr)) where
+instance {-# OVERLAPPING #-} Table t => SqlJustable (PrimaryKey t (QExpr s)) (PrimaryKey t (Nullable (QExpr s))) where
     just_ = pkChangeRep (\(Columnar' q) -> Columnar' (just_ q))
     nothing_ = pkChangeRep (\(Columnar' q) -> Columnar' nothing_) (primaryKey (tblFieldSettings :: TableSettings t))
 
-instance {-# OVERLAPPING #-} Table t => SqlJustable (t QExpr) (t (Nullable QExpr)) where
+instance {-# OVERLAPPING #-} Table t => SqlJustable (t (QExpr s)) (t (Nullable (QExpr s))) where
     just_ = changeRep (\(Columnar' q) -> Columnar' (just_ q))
     nothing_ = changeRep (\(Columnar' q) -> Columnar' nothing_) (tblFieldSettings :: TableSettings t)
 
@@ -503,42 +510,42 @@
 
 -- | Type class for anything which can be checked for null-ness. This includes 'QExpr (Maybe a)' as
 -- well as 'Table's or 'PrimaryKey's over 'Nullable QExpr'.
-class SqlDeconstructMaybe a nonNullA | a -> nonNullA where
+class SqlDeconstructMaybe a nonNullA s | a -> nonNullA, a -> s, nonNullA -> s where
     -- | Returns a 'QExpr' that evaluates to true when the first argument is not null
-    isJust_ :: a -> QExpr Bool
+    isJust_ :: a -> QExpr s Bool
 
     -- | Returns a 'QExpr' that evaluates to true when the first argument is null
-    isNothing_ :: a -> QExpr Bool
+    isNothing_ :: a -> QExpr s Bool
 
     -- | Given an object (third argument) which may or may not be null, return the default value if
     -- null (first argument), or transform the value that could be null to yield the result of the
     -- expression (second argument)
-    maybe_ :: QExpr y -> (nonNullA -> QExpr y) -> a -> QExpr y
+    maybe_ :: QExpr s y -> (nonNullA -> QExpr s y) -> a -> QExpr s y
 
-instance SqlDeconstructMaybe (QExpr (Maybe x)) (QExpr x) where
+instance SqlDeconstructMaybe (QExpr s (Maybe x)) (QExpr s x) s where
     isJust_ (QExpr x) = QExpr (SQLIsJustE x)
     isNothing_ (QExpr x) = QExpr (SQLIsNothingE x)
 
     maybe_ (QExpr onNothing) onJust (QExpr e) = let QExpr onJust' = onJust (QExpr e)
                                                 in QExpr (SQLCaseE [(SQLIsJustE e, onJust')] onNothing)
 
-instance {-# OVERLAPPING #-} Table t => SqlDeconstructMaybe (PrimaryKey t (Nullable QExpr)) (PrimaryKey t QExpr) where
-    isJust_ pk = let fieldsAreJust = pkChangeRep (\(Columnar' x) -> Columnar' (QExprBool (isJust_ x))) pk :: PrimaryKey t QExprBool
+instance {-# OVERLAPPING #-} Table t => SqlDeconstructMaybe (PrimaryKey t (Nullable (QExpr s))) (PrimaryKey t (QExpr s)) s where
+    isJust_ pk = let fieldsAreJust = pkChangeRep (\(Columnar' x) -> Columnar' (QExprBool (isJust_ x))) pk :: PrimaryKey t (QExprBool s)
                  in foldr (&&.) (val_ True) (pkAllValues (\(Columnar' (QExprBool e)) -> e) fieldsAreJust)
-    isNothing_ pk = let fieldsAreNothing = pkChangeRep (\(Columnar' x) -> Columnar' (QExprBool (isNothing_ x))) pk :: PrimaryKey t QExprBool
+    isNothing_ pk = let fieldsAreNothing = pkChangeRep (\(Columnar' x) -> Columnar' (QExprBool (isNothing_ x))) pk :: PrimaryKey t (QExprBool s)
                     in foldr (&&.) (val_ True) (pkAllValues (\(Columnar' (QExprBool e)) -> e) fieldsAreNothing)
     maybe_ = undefined
 
-instance {-# OVERLAPPING #-} Table t  => SqlDeconstructMaybe (t (Nullable QExpr)) (t QExpr) where
-    isJust_ t = let fieldsAreJust = changeRep (\(Columnar' x) -> Columnar' (QExprBool (isJust_ x))) t :: t QExprBool
+instance {-# OVERLAPPING #-} Table t  => SqlDeconstructMaybe (t (Nullable (QExpr s))) (t (QExpr s)) s where
+    isJust_ t = let fieldsAreJust = changeRep (\(Columnar' x) -> Columnar' (QExprBool (isJust_ x))) t :: t (QExprBool s)
                 in foldr (&&.) (val_ True) (fieldAllValues (\(Columnar' (QExprBool e)) -> e) fieldsAreJust)
-    isNothing_ t = let fieldsAreNothing = changeRep (\(Columnar' x) -> Columnar' (QExprBool (isNothing_ x))) t :: t QExprBool
+    isNothing_ t = let fieldsAreNothing = changeRep (\(Columnar' x) -> Columnar' (QExprBool (isNothing_ x))) t :: t (QExprBool s)
                    in foldr (&&.) (val_ True) (fieldAllValues (\(Columnar' (QExprBool e)) -> e) fieldsAreNothing)
     maybe_ = undefined
 
 class BeamUnwrapMaybe c where
     beamUnwrapMaybe :: Columnar' (Nullable c) x -> Columnar' c x
-instance BeamUnwrapMaybe QExpr where
+instance BeamUnwrapMaybe (QExpr s) where
     beamUnwrapMaybe (Columnar' (QExpr e)) = Columnar' (QExpr e)
 instance BeamUnwrapMaybe c => BeamUnwrapMaybe (Nullable c) where
     beamUnwrapMaybe (Columnar' x :: Columnar' (Nullable (Nullable c)) x) =
@@ -548,12 +555,12 @@
             xCol = Columnar' x'
         in xCol
 
-instance {-# OVERLAPPING #-} ( SqlDeconstructMaybe (PrimaryKey t (Nullable c)) res, Table t, BeamUnwrapMaybe (Nullable c)) => SqlDeconstructMaybe (PrimaryKey t (Nullable (Nullable c))) res where
+instance {-# OVERLAPPING #-} ( SqlDeconstructMaybe (PrimaryKey t (Nullable c)) res s, Table t, BeamUnwrapMaybe (Nullable c)) => SqlDeconstructMaybe (PrimaryKey t (Nullable (Nullable c))) res s where
     isJust_ t = isJust_ (pkChangeRep (\(f :: Columnar' (Nullable (Nullable c)) x) -> beamUnwrapMaybe f :: Columnar' (Nullable c) x) t)
     isNothing_ t = isNothing_ (pkChangeRep (\(f :: Columnar' (Nullable (Nullable c)) x) -> beamUnwrapMaybe f :: Columnar' (Nullable c) x) t)
     maybe_ = undefined
 
-instance {-# OVERLAPPING #-} ( SqlDeconstructMaybe (t (Nullable c)) res, Table t, BeamUnwrapMaybe (Nullable c)) => SqlDeconstructMaybe (t (Nullable (Nullable c))) res where
+instance {-# OVERLAPPING #-} ( SqlDeconstructMaybe (t (Nullable c)) res s, Table t, BeamUnwrapMaybe (Nullable c)) => SqlDeconstructMaybe (t (Nullable (Nullable c))) res s where
     isJust_ t = isJust_ (changeRep (\(f :: Columnar' (Nullable (Nullable c)) x) -> beamUnwrapMaybe f :: Columnar' (Nullable c) x) t)
     isNothing_ t = isNothing_ (changeRep (\(f :: Columnar' (Nullable (Nullable c)) x) -> beamUnwrapMaybe f :: Columnar' (Nullable c) x) t)
     maybe_ = undefined
diff --git a/src/Database/Beam/Query/Internal.hs b/src/Database/Beam/Query/Internal.hs
--- a/src/Database/Beam/Query/Internal.hs
+++ b/src/Database/Beam/Query/Internal.hs
@@ -29,10 +29,12 @@
 --   directly to 'query' or 'queryList'
 newtype TopLevelQ db s a = TopLevelQ (Q db s a)
 
+data QNested s
+
 data QueryBuilder = QueryBuilder
                   { qbNextTblRef :: Int
                   , qbFrom  :: Maybe SQLFrom
-                  , qbWhere :: QExpr Bool
+                  , qbWhere :: SQLExpr' QField
 
                   , qbLimit  :: Maybe Integer
                   , qbOffset :: Maybe Integer
@@ -50,13 +52,13 @@
 -- | The type of lifted beam expressions that will yield the haskell type `t` when run with
 -- `queryList` or `query`. In the future, this will include a thread argument meant to prevent
 -- cross-usage of expressions, but this is unimplemented for technical reasons.
-newtype QExpr t = QExpr (SQLExpr' QField)
+newtype QExpr s t = QExpr (SQLExpr' QField)
     deriving (Show, Eq)
 
 -- * Aggregations
 
-data Aggregation a = GroupAgg (SQLExpr' QField)
-                   | ProjectAgg (SQLExpr' QField)
+data Aggregation s a = GroupAgg (SQLExpr' QField)
+                     | ProjectAgg (SQLExpr' QField)
 
 -- * Sql Projections
 --
@@ -67,7 +69,7 @@
 
 class Projectible a where
     project :: a -> [SQLExpr' QField]
-instance Typeable a => Projectible (QExpr a) where
+instance Typeable a => Projectible (QExpr s a) where
     project (QExpr x) = [x]
 instance Projectible () where
     project () = [SQLValE (SqlInteger 1)]
@@ -89,12 +91,12 @@
          , Projectible e ) => Projectible (a, b, c, d, e) where
     project (a, b, c, d, e) = project a ++ project b ++ project c ++ project d ++ project e
 
-instance Table t => Projectible (t QExpr) where
+instance Table t => Projectible (t (QExpr s)) where
     project t = fieldAllValues (\(Columnar' (QExpr e)) -> e) t
-instance Table t => Projectible (t (Nullable QExpr)) where
+instance Table t => Projectible (t (Nullable (QExpr s))) where
     project t = fieldAllValues (\(Columnar' (QExpr e)) -> e) t
 
-tableVal :: Table tbl => tbl Identity -> tbl QExpr
+tableVal :: Table tbl => tbl Identity -> tbl (QExpr s)
 tableVal = changeRep valToQExpr . makeSqlValues
-    where valToQExpr :: Columnar' SqlValue' a -> Columnar' QExpr a
+    where valToQExpr :: Columnar' SqlValue' a -> Columnar' (QExpr s) a
           valToQExpr (Columnar' (SqlValue' v)) = Columnar' (QExpr (SQLValE v))
diff --git a/src/Database/Beam/Query/Types.hs b/src/Database/Beam/Query/Types.hs
--- a/src/Database/Beam/Query/Types.hs
+++ b/src/Database/Beam/Query/Types.hs
@@ -36,9 +36,9 @@
 -- * Beam queries
 
 type family QExprToIdentity x
-type instance QExprToIdentity (table QExpr) = table Identity
+type instance QExprToIdentity (table (QExpr s)) = table Identity
 type instance QExprToIdentity (table (Nullable c)) = Maybe (QExprToIdentity (table c))
-type instance QExprToIdentity (QExpr a) = a
+type instance QExprToIdentity (QExpr s a) = a
 type instance QExprToIdentity (a, b) = (QExprToIdentity a, QExprToIdentity b)
 type instance QExprToIdentity (a, b, c) = (QExprToIdentity a, QExprToIdentity b, QExprToIdentity c)
 type instance QExprToIdentity (a, b, c, d) = (QExprToIdentity a, QExprToIdentity b, QExprToIdentity c, QExprToIdentity d)
@@ -73,7 +73,7 @@
 optimizeExpr' = runIdentity . rewriteM allExprOpts . fmap mkSqlField
 
 -- | Optimize a `QExpr` and turn it in into a `SQLExpr`.
-optimizeExpr :: QExpr a -> SQLExpr
+optimizeExpr :: QExpr s a -> SQLExpr
 optimizeExpr (QExpr e) = optimizeExpr' e
 
 mkSqlField :: QField -> SQLFieldName
@@ -83,13 +83,13 @@
 -- | Turn a `Q` into a `SQLSelect` starting the table references at the given number
 queryToSQL' :: Projectible a => Q db s a -> Int -> (a, Int, SQLSelect)
 queryToSQL' q curTbl = let (res, qb) = runState (runQ q) emptyQb
-                           emptyQb = QueryBuilder curTbl Nothing (QExpr (SQLValE (SqlBool True))) Nothing Nothing [] Nothing
+                           emptyQb = QueryBuilder curTbl Nothing (SQLValE (SqlBool True)) Nothing Nothing [] Nothing
                            projection = map (\q -> SQLAliased (optimizeExpr' q) Nothing) (project res)
 
                            sel = SQLSelect
                                  { selProjection = SQLProj projection
                                  , selFrom = qbFrom qb
-                                 , selWhere = optimizeExpr (qbWhere qb)
+                                 , selWhere = optimizeExpr' (qbWhere qb)
                                  , selGrouping = qbGrouping qb
                                  , selOrderBy = qbOrdering qb
                                  , selLimit = qbLimit qb
