diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -8,8 +8,8 @@
             - [Conditionals](#conditionals)
             - [Limited `CREATE TABLE` support.](#limited-create-table-support)
             - [`INSERT INTO` support.](#insert-into-support)
+            - [`DELETE FROM` support.](#delete-from-support)
     - [Roadmap](#roadmap)
-        - [DELETE support](#delete-support)
         - [UPDATE support](#update-support)
         - [Flesh out Haskell to PostgreSQL type mapping.](#flesh-out-haskell-to-postgresql-type-mapping)
     - [How it compares with other libraries.](#how-it-compares-with-other-libraries)
@@ -69,7 +69,7 @@
 We support queries of the form:
 
 ```haskell
-type MyQuery = Select '["t1.field1", "t2.field2"] `From` MyTable1 `As` "t1" `X` MyTable2 `As` "t2"
+type MyQuery = Select '["t1.field1", "t2.field2"] `From` '[MyTable1 `As` "t1", MyTable2 `As` "t2"]
 ```
 
 #### Conditionals
@@ -129,14 +129,29 @@
   (Only 1 :> Only "Bob Marley" :> Only 36)
 ```
 
-## Roadmap
+#### `DELETE FROM` support.
 
-This is what I plan to work on next:
+Basic deletes are supported:
 
-### DELETE support
+```haskell
+type MyDeleteEveryone = DeleteFrom PeopleTable
+type MyDeleteById = DeleteFrom PeopleTable `Where` id `Equals` (?)
 
-Support delete operations.
+execute
+  conn
+  (Proxy :: Proxy MyDeleteEveryone)
+  ()
 
+execute
+  conn
+  (Proxy :: Proxy MyDeleteById)
+  (Only 1)
+```
+
+## Roadmap
+
+This is what I plan to work on next:
+
 ### UPDATE support
 
 Support update operations.
@@ -181,11 +196,11 @@
 
   Then you would be free to deconstruct this type (using type families),
   transform it into another schema, generate customized `CREATE TABLE`
-  statements if the (forthcoming) ones provided aren't good enough for your
-  back-end or use case... that sort of thing. As a somewhat contrived example:
-  maybe, for who knows what reason, you never want to allow null values in your
-  database. You can write a type family that can inspect every field in an
-  arbitrary schema, replacing all the `Maybe a` with just `a`, like:
+  statements if the ones provided aren't good enough for your back-end or
+  use case... that sort of thing. As a somewhat contrived example: maybe,
+  for who knows what reason, you never want to allow null values in your
+  database. You can write a type family that can inspect every field in
+  an arbitrary schema, replacing all the `Maybe a` with just `a`, like:
 
   ```haskell
   -- With -XPolyKinds
diff --git a/ribbit.cabal b/ribbit.cabal
--- a/ribbit.cabal
+++ b/ribbit.cabal
@@ -1,6 +1,6 @@
 
 name:                ribbit
-version:             0.3.0.1
+version:             0.4.0.0
 synopsis:            Type-level Relational DB combinators.
 description:         Ribbit is yet another type safe relational database
                      library for Haskell, heavily inspired by the
diff --git a/src/Database/Ribbit.hs b/src/Database/Ribbit.hs
--- a/src/Database/Ribbit.hs
+++ b/src/Database/Ribbit.hs
@@ -47,6 +47,9 @@
   -- ** Inserting values
   -- $insert
 
+  -- ** Deleting values
+  -- $delete
+
   -- * Schema Definition Types
   (:>)(..),
   Table(..),
@@ -55,12 +58,14 @@
   -- * Query Combinators
   Select,
   From,
-  X,
   As,
   Where,
 
   -- * Insert Combinators
   InsertInto,
+  
+  -- * Delete Combinators
+  DeleteFrom,
 
   -- ** Condition Conbinators
   And,
@@ -160,7 +165,10 @@
 -- > type MyQuery =
 -- >   Select '["e.name", "e.salary"]
 -- >   `From`
--- >     Company `As` "c" `X` Employee `As` "e"
+-- >       '[
+-- >         Company `As` "c",
+-- >         Employee `As` "e"
+-- >       ]
 -- >   `Where`
 -- >     "c.id" `Equals` "e.company_id"
 -- >     `And` "c.name" `Equals` (?)
@@ -259,7 +267,35 @@
 -- >     (Proxy :: Proxy InsertEmployee)
 -- >     (Only 1 :> Only 1 :> Only "Rick" :> Only myBirthday)
 
+-- $delete
+-- Deleting a value is similar to inserting a value, but simpler because
+-- you only have to specify the delete conditions (if there are any).
+-- 
+-- e.g.:
+--  
+-- > type DeleteAllEmployees = DeleteFrom Employee
+-- > type DeleteEmployeeById =
+-- >   DeleteFrom Employee
+-- >   `Where` "id" `Equals` (?)
+-- 
+-- Then just execute the query, providing the appropriate query params.
+-- 
+-- > do
+-- >   let
+-- >     employeeId :: Int
+-- >     employeeId = ...
+-- >   execute
+-- >     conn
+-- >     (Proxy :: Proxy DeleteEmployeeById)
+-- >     (Only employeeId)
+-- >
+-- >   -- Or maybe delete all employees.
+-- >   execute
+-- >     conn
+-- >     (Proxy :: Proxy DeleteAllEmployees)
+-- >     ()
 
+
 {- | "SELECT" combinator, used for starting a @SELECT@ statement. -}
 data Select fields
 
@@ -317,11 +353,6 @@
 infixr 7 `Or`
 
 
-{- | Cross product operator for FROM clauses. -}
-data X l r
-infixr 7 `X`
-
-
 {- | "AS" combinator, used for attaching a name to a table in a FROM clause. -}
 data As relation name
 infix 8 `As`
@@ -399,7 +430,6 @@
   LookupType name a context = NotInSchema name context
 
 
-
 {- |
   Type class for defining your own tables. The primary way for you to
   introduce a new schema is to instantiate this type class for one of
@@ -421,20 +451,42 @@
   type DBSchema relation
 
 {- | Cross product -}
-instance (Table l, Table r, KnownSymbol lname, KnownSymbol rname) => Table (l `As` lname `X` r `As` rname) where
-  type DBSchema (l `As` lname `X` r `As` rname) =
+instance
+    (Table table, KnownSymbol name)
+  =>
+    Table ((table `As` name) : moreTables)
+  where
+    type DBSchema ((table `As` name) : moreTables) =
+      CrossProductSchema ((table `As` name) : moreTables)
+    type Name ((table `As` name) : moreTables) =
+      CrossProductName ((table `As` name) : moreTables)
+
+
+{- | Produce the schema of a cross product. -}
+type family CrossProductSchema cp where
+  CrossProductSchema '[table `as` name] =
     Flatten (
-      AliasAs lname (DBSchema l)
-      :> AliasAs rname (DBSchema r)
+      AliasAs name (DBSchema table)
     )
-  type Name (l `As` lname `X` r `As` rname) =
-    Name l
+  CrossProductSchema ((table `As` name) : moreTables) =
+    Flatten (
+      AliasAs name (DBSchema table)
+      :> CrossProductSchema moreTables
+    )
+
+
+{- | Product the renderable "name" of a cross product. -}
+type family CrossProductName cp where
+  CrossProductName '[table `As` name] = 
+    Name table
     `AppendSymbol` " as "
-    `AppendSymbol` lname
-    `AppendSymbol` ", "
-    `AppendSymbol` Name r
+    `AppendSymbol` name
+  CrossProductName ((table `As` name) : moreTables) = 
+    Name table
     `AppendSymbol` " as "
-    `AppendSymbol` rname
+    `AppendSymbol` name
+    `AppendSymbol` ", "
+    `AppendSymbol` CrossProductName moreTables
 
 
 {- |
@@ -469,6 +521,8 @@
 type family ArgsType query where
   ArgsType (_ `From` relation `Where` conditions) =
     ArgsType (DBSchema relation, conditions)
+  ArgsType (DeleteFrom relation `Where` conditions) =
+    ArgsType (DBSchema relation, conditions)
   ArgsType (InsertInto relation '[]) =
     TypeError ('Lit.Text "Insert statement must specify at least one column.")
   ArgsType (InsertInto relation fields) =
@@ -654,15 +708,25 @@
   render _proxy = "?"
 
 {- INSERT -}
-instance (ReflectFields fields, KnownSymbol (Name table)) => Render (InsertInto table fields) where
+instance
+    (ReflectFields fields, KnownSymbol (Name table))
+  =>
+    Render (InsertInto table fields)
+  where
+    render _proxy =
+      let
+        fields :: [Text]
+        fields = reflectFields (Proxy @fields)
+      in
+        "insert into " <> symbolVal (Proxy @(Name table))
+        <> " (" <> T.intercalate ", " fields <> ")"
+        <> " values (" <> T.intercalate ", " (const "?" <$> fields) <> ");"
+
+
+{- DELETE -}
+instance (KnownSymbol (Name table)) => Render (DeleteFrom table) where
   render _proxy =
-    let
-      fields :: [Text]
-      fields = reflectFields (Proxy @fields)
-    in
-      "insert into " <> symbolVal (Proxy @(Name table))
-      <> " (" <> T.intercalate ", " fields <> ")"
-      <> " values (" <> T.intercalate ", " (const "?" <$> fields) <> ");"
+    "delete from " <> symbolVal (Proxy @(Name table))
 
 
 {- | Insert statement. -}
@@ -676,5 +740,9 @@
   reflectFields _proxy = []
 instance (KnownSymbol a, ReflectFields more) => ReflectFields (a:more) where
   reflectFields _proxy = symbolVal (Proxy @a) : reflectFields (Proxy @more)
+
+
+{- | Delete statement. -}
+data DeleteFrom table
 
 
