diff --git a/cqrs.cabal b/cqrs.cabal
--- a/cqrs.cabal
+++ b/cqrs.cabal
@@ -1,5 +1,5 @@
 Name:                cqrs
-Version:             0.6.0
+Version:             0.7.0
 Synopsis:            Command-Query Responsibility Segregation
 Description:         Haskell implementation of the CQRS architectural pattern.
 License:             MIT
@@ -16,8 +16,8 @@
                , bytestring >= 0.9.0.1
                , cereal >= 0.3.3 && < 0.4
                , containers >= 0.4
-               , enumerator >= 0.4.15 && < 0.5
                , data-default >= 0.3 && < 0.4
+               , enumerator >= 0.4.15 && < 0.5
                , random >= 1.0 && < 1.1
                , transformers >= 0.2.2 && < 0.3
   Extensions:          DeriveDataTypeable
@@ -37,7 +37,9 @@
                        Data.CQRS.EventStore
                        Data.CQRS.EventStore.Backend
                        Data.CQRS.GUID
+                       Data.CQRS.PersistedEvent
                        Data.CQRS.Serialize
                        Data.CQRS.Transaction
   Other-modules:       Data.CQRS.Internal.AggregateRef
                        Data.CQRS.Internal.EventStore
+                       Data.CQRS.Internal.PersistedEvent
diff --git a/src/Data/CQRS/EventStore/Backend.hs b/src/Data/CQRS/EventStore/Backend.hs
--- a/src/Data/CQRS/EventStore/Backend.hs
+++ b/src/Data/CQRS/EventStore/Backend.hs
@@ -3,12 +3,18 @@
 -- event store backend.
 module Data.CQRS.EventStore.Backend
        ( EventStoreBackend(..)
+       , RawEvent
        ) where
 
 import Data.ByteString (ByteString)
 import Data.CQRS.GUID
+import Data.CQRS.PersistedEvent (PersistedEvent)
 import Data.Enumerator (Enumerator)
 
+-- | Raw event type. The data associated with an event is not
+-- translated in any way.
+type RawEvent = PersistedEvent ByteString
+
 -- | Event stores are the backend used for reading and storing all the
 -- information about recorded events.
 data EventStoreBackend =
@@ -17,15 +23,14 @@
     -- into the event store, starting at the provided version number.
     -- If the version number does not match the expected value, a
     -- failure occurs.
-    esbStoreEvents :: GUID -> Int -> [(ByteString,Int)] -> IO (),
+    esbStoreEvents :: GUID -> Int -> [RawEvent] -> IO (),
     -- | Retrieve the sequence of events associated with the aggregate
     -- identified by the given GUID. Only events at or after the given
     -- version number are retrieved. The events are returned in
-    -- increasing order of version number. The version number of the
-    -- last event is returned as well.
-    esbRetrieveEvents :: GUID -> Int -> IO (Int,[ByteString]),
+    -- increasing order of version number.
+    esbRetrieveEvents :: GUID -> Int -> IO [RawEvent],
     -- | Enumerate all events later than given logical timestamp.
-    esbEnumerateAllEvents :: forall a. Int -> Enumerator (Int, (GUID, Int, ByteString)) IO a,
+    esbEnumerateAllEvents :: forall a. Int -> Enumerator RawEvent IO a,
     -- | Write snapshot for aggregate identified by GUID and
     -- the given version number. The version number is NOT checked
     -- for validity. If the event store does not support snapshots
diff --git a/src/Data/CQRS/GUID.hs b/src/Data/CQRS/GUID.hs
--- a/src/Data/CQRS/GUID.hs
+++ b/src/Data/CQRS/GUID.hs
@@ -1,9 +1,11 @@
 -- | Globally Unique IDentifiers.
 module Data.CQRS.GUID
        ( GUID
+       , fromByteString
        , hexDecode
        , hexEncode
        , newGUID
+       , toByteString
        ) where
 
 import           Control.Monad (liftM)
@@ -37,8 +39,8 @@
 
 -- | Serialize instance.
 instance Serialize GUID where
-    put (GUID s) = put s
-    get = liftM GUID get
+    put = put . toByteString
+    get = liftM fromByteString get
 
 -- | Hex encode a GUID.
 hexEncode :: GUID -> ByteString
@@ -50,3 +52,11 @@
   case B16.decode s of
     (a,b) | B.length b == 0 -> Just $ GUID a
     _                       -> Nothing
+
+-- | Convert from ByteString.
+fromByteString :: ByteString -> GUID
+fromByteString = GUID
+
+-- | Convert to ByteString.
+toByteString :: GUID -> ByteString
+toByteString (GUID g) = g
diff --git a/src/Data/CQRS/Internal/AggregateRef.hs b/src/Data/CQRS/Internal/AggregateRef.hs
--- a/src/Data/CQRS/Internal/AggregateRef.hs
+++ b/src/Data/CQRS/Internal/AggregateRef.hs
@@ -12,8 +12,9 @@
 
 import           Control.Monad (liftM)
 import           Control.Monad.IO.Class (MonadIO, liftIO)
-import           Data.CQRS.GUID (GUID)
 import           Data.CQRS.Eventable (Eventable(..))
+import           Data.CQRS.GUID (GUID)
+import           Data.CQRS.PersistedEvent (PersistedEvent(..))
 import           Data.Foldable (toList)
 import           Data.IORef (IORef, modifyIORef, newIORef, readIORef)
 import           Data.Sequence (Seq, (|>))
@@ -23,7 +24,7 @@
 -- | Aggregate root reference.
 data AggregateRef a e =
   AggregateRef { arValue :: IORef a
-               , arEvents :: IORef (Seq (e, Int))
+               , arEvents :: IORef (Seq (PersistedEvent e))
                , arGUID :: GUID
                , arStartVersion :: Int
                , arSnapshotVersion :: Int
@@ -43,10 +44,11 @@
   -- Apply event to aggregate state.
   modifyIORef (arValue aggregateRef) $ applyEvent event
   -- Add event to aggregate.
-  modifyIORef (arEvents aggregateRef) $ \events -> events |> (event,gv)
+  modifyIORef (arEvents aggregateRef) $ \events ->
+    events |> (PersistedEvent (arGUID aggregateRef) event (arStartVersion aggregateRef + 1 + S.length events) gv)
 
 -- | Read aggregate events.
-readEvents :: (MonadIO m) => AggregateRef a e -> m [(e,Int)]
+readEvents :: (MonadIO m) => AggregateRef a e -> m [PersistedEvent e]
 readEvents = liftM toList . liftIO . readIORef . arEvents
 
 -- | Read aggregate state.
diff --git a/src/Data/CQRS/Internal/EventStore.hs b/src/Data/CQRS/Internal/EventStore.hs
--- a/src/Data/CQRS/Internal/EventStore.hs
+++ b/src/Data/CQRS/Internal/EventStore.hs
@@ -1,7 +1,6 @@
 -- | Event store functions.
 module Data.CQRS.Internal.EventStore
        ( EventStore
-       , enumerateAllEvents
        , enumerateEventStore
        , getLatestSnapshot
        , getLatestVersion
@@ -17,21 +16,12 @@
 import           Data.ByteString (ByteString)
 import           Data.CQRS.EventStore.Backend (EventStoreBackend(..))
 import           Data.CQRS.GUID
+import           Data.CQRS.Internal.PersistedEvent (PersistedEvent(..), mapPersistedEvent)
 import           Data.CQRS.Serialize (decode')
 import           Data.Enumerator (Enumerator, ($=))
 import qualified Data.Enumerator.List as EL
 import           Data.Serialize (Serialize, encode)
 
--- Utilities.
-map1st :: (a -> c) -> (a, b) -> (c, b)
-map1st f (a,b) = (f a, b)
-
-map2nd :: (b -> c) -> (a,b) -> (a,c)
-map2nd f (a,b) = (a, f b)
-
-map3rd :: (c -> d) -> (a,b,c) -> (a,b,d)
-map3rd f (a,b,c) = (a,b,f c)
-
 -- Provide a type alias.
 data EventStore e = EventStore { esBackend :: EventStoreBackend
                                }
@@ -42,22 +32,18 @@
 
 -- | Enumerate all the events from an event store that occur at or later
 -- than a given logical timestamp.
-enumerateEventStore :: forall a e . (Serialize e) => EventStore e -> Int -> Enumerator (Int, (GUID, Int, e)) IO a
+enumerateEventStore :: forall a e . (Serialize e) => EventStore e -> Int -> Enumerator (PersistedEvent e) IO a
 enumerateEventStore es minVersion =
-  esbEnumerateAllEvents (esBackend es) minVersion $= EL.map (\(gv,(g,ev,ed)) -> (gv,(g,ev,decode' ed :: e)))
+  esbEnumerateAllEvents (esBackend es) minVersion $= EL.map (mapPersistedEvent decode')
 
 withTransaction :: EventStore e -> IO a -> IO a
 withTransaction (EventStore esb) = esbWithTransaction esb
 
-storeEvents :: Serialize e => EventStore e -> GUID -> Int -> [(e,Int)] -> IO ()
-storeEvents (EventStore esb) guid v0 evs = esbStoreEvents esb guid v0 (map (map1st encode) evs)
-
-retrieveEvents :: Serialize e => EventStore e -> GUID -> Int -> IO (Int,[e])
-retrieveEvents (EventStore esb) guid v0 = liftM (map2nd $ map decode') $ esbRetrieveEvents esb guid v0
+storeEvents :: Serialize e => EventStore e -> GUID -> Int -> [PersistedEvent e] -> IO ()
+storeEvents (EventStore esb) guid v0 evs = esbStoreEvents esb guid v0 $ (map $ mapPersistedEvent encode) evs
 
-enumerateAllEvents :: forall a e. Serialize e => EventStore e -> Int -> Enumerator (Int, (GUID, Int, e)) IO a
-enumerateAllEvents (EventStore esb) v0 =
-  esbEnumerateAllEvents esb v0 $= EL.map (map2nd $ map3rd decode')
+retrieveEvents :: Serialize e => EventStore e -> GUID -> Int -> IO [PersistedEvent e]
+retrieveEvents (EventStore esb) guid v0 = liftM (map $ mapPersistedEvent decode') $ esbRetrieveEvents esb guid v0
 
 writeSnapshot ::   EventStore e -> GUID -> (Int, ByteString) -> IO ()
 writeSnapshot (EventStore esb) = esbWriteSnapshot esb
diff --git a/src/Data/CQRS/Internal/PersistedEvent.hs b/src/Data/CQRS/Internal/PersistedEvent.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/CQRS/Internal/PersistedEvent.hs
@@ -0,0 +1,18 @@
+module Data.CQRS.Internal.PersistedEvent
+       ( PersistedEvent(..)
+       , mapPersistedEvent
+       ) where
+
+import Data.CQRS.GUID (GUID)
+
+-- | Persisted Event.
+data PersistedEvent e =
+  PersistedEvent { peAggregateGUID :: !GUID -- ^ GUID of the aggregate.
+                 , peEvent :: e             -- ^ Event.
+                 , peSequenceNumber :: !Int -- ^ Sequence number within the aggregate.
+                 , peGlobalVer :: !Int      -- ^ Global sequence number.
+                 }
+
+-- Transform the event data.
+mapPersistedEvent :: (e -> e') -> PersistedEvent e -> PersistedEvent e'
+mapPersistedEvent f (PersistedEvent g e v gv) = PersistedEvent g (f e) v gv
diff --git a/src/Data/CQRS/PersistedEvent.hs b/src/Data/CQRS/PersistedEvent.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/CQRS/PersistedEvent.hs
@@ -0,0 +1,5 @@
+module Data.CQRS.PersistedEvent
+       ( PersistedEvent(..)
+       ) where
+
+import Data.CQRS.Internal.PersistedEvent
diff --git a/src/Data/CQRS/Transaction.hs b/src/Data/CQRS/Transaction.hs
--- a/src/Data/CQRS/Transaction.hs
+++ b/src/Data/CQRS/Transaction.hs
@@ -11,12 +11,13 @@
 import           Control.Monad.Trans.Class (MonadTrans(..), lift)
 import           Control.Monad.Trans.State (StateT, get, gets, modify, runStateT)
 import           Data.CQRS.Aggregate (Aggregate(..))
-import           Data.CQRS.Internal.AggregateRef (AggregateRef, mkAggregateRef)
-import qualified Data.CQRS.Internal.AggregateRef as AR
 import           Data.CQRS.Eventable (Eventable(..))
 import           Data.CQRS.EventStore (EventStore)
-import qualified Data.CQRS.Internal.EventStore as ES
 import           Data.CQRS.GUID (GUID)
+import           Data.CQRS.Internal.AggregateRef (AggregateRef, mkAggregateRef)
+import qualified Data.CQRS.Internal.AggregateRef as AR
+import qualified Data.CQRS.Internal.EventStore as ES
+import           Data.CQRS.PersistedEvent (PersistedEvent(..))
 import           Data.Default (Default(..))
 import           Data.List (find)
 import           Data.Serialize (Serialize)
@@ -102,9 +103,10 @@
   -- Get latest snapshot (if any).
   (v0,a0) <- getLatestSnapshot guid
   -- Get events.
-  (latestVersion, events) <- lift $ ES.retrieveEvents es guid v0
+  events <- lift $ ES.retrieveEvents es guid v0
+  let latestVersion = maximum $ (:) v0 (map peSequenceNumber events)
   -- Build the aggregate state from all the events.
-  let a = foldr applyEvent a0 events
+  let a = foldr (applyEvent . peEvent) a0 events
   -- Make the aggregate itself
   (a' :: AggregateRef a e) <- lift $ mkAggregateRef a guid latestVersion v0
   -- Add to set of aggregates to commit later.
