diff --git a/esqueleto.cabal b/esqueleto.cabal
--- a/esqueleto.cabal
+++ b/esqueleto.cabal
@@ -1,5 +1,5 @@
 name:                esqueleto
-version:             2.2.12
+version:             2.3.0
 synopsis:            Type-safe EDSL for SQL queries on persistent backends.
 homepage:            https://github.com/prowdsponsor/esqueleto
 license:             BSD3
@@ -64,6 +64,7 @@
     Database.Esqueleto.Internal.PersistentImport
   build-depends:
       base                 >= 4.5     && < 4.9
+    , bytestring
     , text                 >= 0.11    && < 1.3
     , persistent           >= 2.1.1.7 && < 2.3
     , transformers         >= 0.2
@@ -73,6 +74,7 @@
     , monad-logger
     , conduit              >= 1.1
     , resourcet            >= 1.1
+    , blaze-html
   hs-source-dirs: src/
   ghc-options: -Wall
 
diff --git a/src/Database/Esqueleto.hs b/src/Database/Esqueleto.hs
--- a/src/Database/Esqueleto.hs
+++ b/src/Database/Esqueleto.hs
@@ -62,6 +62,7 @@
   , OrderBy
   , DistinctOn
   , LockingKind(..)
+  , SqlString
     -- ** Joins
   , InnerJoin(..)
   , CrossJoin(..)
diff --git a/src/Database/Esqueleto/Internal/Language.hs b/src/Database/Esqueleto/Internal/Language.hs
--- a/src/Database/Esqueleto/Internal/Language.hs
+++ b/src/Database/Esqueleto/Internal/Language.hs
@@ -31,6 +31,7 @@
   , Update
   , Insertion
   , LockingKind(..)
+  , SqlString
     -- * The guts
   , JoinKind(..)
   , IsJoinKind(..)
@@ -45,11 +46,16 @@
 import Control.Applicative (Applicative(..), (<$>))
 import Control.Exception (Exception)
 import Data.Int (Int64)
-import Data.String (IsString)
 import Data.Typeable (Typeable)
 import Database.Esqueleto.Internal.PersistentImport
+import Text.Blaze.Html (Html)
 
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
 
+
 -- | Finally tagless representation of @esqueleto@'s EDSL.
 class (Functor query, Applicative query, Monad query) =>
       Esqueleto query expr backend | query -> expr backend, expr -> query backend where
@@ -391,15 +397,15 @@
   coalesceDefault :: PersistField a => [expr (Value (Maybe a))] -> expr (Value a) -> expr (Value a)
 
   -- | @LOWER@ function.
-  lower_ :: (PersistField a, IsString a) => expr (Value a) -> expr (Value a)
+  lower_ :: (PersistField a, SqlString a) => expr (Value a) -> expr (Value a)
   -- | @LIKE@ operator.
-  like :: (PersistField s, IsString s) => expr (Value s) -> expr (Value s) -> expr (Value Bool)
+  like :: (PersistField s, SqlString s) => expr (Value s) -> expr (Value s) -> expr (Value Bool)
   -- | @ILIKE@ operator (case-insensitive @LIKE@).
   --
   -- Supported by PostgreSQL only.
   --
   -- /Since: 2.2.3/
-  ilike :: (PersistField s, IsString s) => expr (Value s) -> expr (Value s) -> expr (Value Bool)
+  ilike :: (PersistField s, SqlString s) => expr (Value s) -> expr (Value s) -> expr (Value Bool)
   -- | The string @'%'@.  May be useful while using 'like' and
   -- concatenation ('concat_' or '++.', depending on your
   -- database).  Note that you always to type the parenthesis,
@@ -408,14 +414,14 @@
   -- @
   -- name `'like`` (%) ++. 'val' \"John\" ++. (%)
   -- @
-  (%) :: (PersistField s, IsString s) => expr (Value s)
+  (%) :: (PersistField s, SqlString s) => expr (Value s)
   -- | The @CONCAT@ function with a variable number of
   -- parameters.  Supported by MySQL and PostgreSQL.
-  concat_ :: (PersistField s, IsString s) => [expr (Value s)] -> expr (Value s)
+  concat_ :: (PersistField s, SqlString s) => [expr (Value s)] -> expr (Value s)
   -- | The @||@ string concatenation operator (named after
   -- Haskell's '++' in order to avoid naming clash with '||.').
   -- Supported by SQLite and PostgreSQL.
-  (++.) :: (PersistField s, IsString s) => expr (Value s) -> expr (Value s) -> expr (Value s)
+  (++.) :: (PersistField s, SqlString s) => expr (Value s) -> expr (Value s) -> expr (Value s)
 
   -- | Execute a subquery @SELECT@ in an expression.  Returns a
   -- list of values.
@@ -767,6 +773,36 @@
     -- ^ @LOCK IN SHARE MODE@ syntax.  Supported by MySQL.
     --
     -- /Since: 2.2.7/
+
+
+-- | Phantom class of data types that are treated as strings by the
+-- RDBMS.  It has no methods because it's only used to avoid type
+-- errors such as trying to concatenate integers.
+--
+-- If you have a custom data type or @newtype@, feel free to make
+-- it an instance of this class.
+--
+-- /Since: 2.3.0/
+class SqlString a where
+
+-- | /Since: 2.3.0/
+instance (a ~ Char) => SqlString [a] where
+
+-- | /Since: 2.3.0/
+instance SqlString T.Text where
+
+-- | /Since: 2.3.0/
+instance SqlString TL.Text where
+
+-- | /Since: 2.3.0/
+instance SqlString B.ByteString where
+
+-- | /Since: 2.3.0/
+instance SqlString BL.ByteString where
+
+-- | /Since: 2.3.0/
+instance SqlString Html where
+
 
 
 -- | @FROM@ clause: bring entities into scope.
diff --git a/src/Database/Esqueleto/PostgreSQL.hs b/src/Database/Esqueleto/PostgreSQL.hs
--- a/src/Database/Esqueleto/PostgreSQL.hs
+++ b/src/Database/Esqueleto/PostgreSQL.hs
@@ -9,8 +9,6 @@
   , chr
   ) where
 
-import Data.String (IsString)
-
 import Database.Esqueleto.Internal.Language
 import Database.Esqueleto.Internal.Sql
 
@@ -28,7 +26,7 @@
 --
 -- /Since: 2.2.8/
 stringAgg
-  :: IsString s
+  :: SqlString s
   => SqlExpr (Value s) -- ^ Input values.
   -> SqlExpr (Value s) -- ^ Delimiter.
   -> SqlExpr (Value s) -- ^ Concatenation.
@@ -39,6 +37,5 @@
 -- depend on the character set of your database.)
 --
 -- /Since: 2.2.11/
-chr :: IsString s
-    => SqlExpr (Value Int) -> SqlExpr (Value s)
+chr :: SqlString s => SqlExpr (Value Int) -> SqlExpr (Value s)
 chr = unsafeSqlFunction "chr"
