diff --git a/src/structs/ContentLink.js b/src/structs/ContentLink.js
index 5598f828..1bdba6c7 100644
--- a/src/structs/ContentLink.js
+++ b/src/structs/ContentLink.js
@@ -15,10 +15,12 @@ import {
   
   export class ContentLink {
     /**
-     * @param {WeakLink<any>|{parent:string|ID,item:string|ID}} link
+     * @param {WeakLink<any>|null} link
+     * @param {{type:ID|null,tname:string|null,item:ID|null,key:string|null}|null} raw
      */
-    constructor (link) {
+    constructor (link, raw) {
       this.link = link
+      this.raw = raw
     }
   
     /**
@@ -46,7 +48,7 @@ import {
      * @return {ContentLink}
      */
     copy () {
-      return new ContentLink(this.link)
+      return new ContentLink(this.link, this.raw)
     }
   
     /**
@@ -70,38 +72,40 @@ import {
      * @param {Item} item
      */
     integrate (transaction, item) {
-      if (this.link.constructor !== WeakLink) {
-        let { parent, item } = /** @type {any} */ (this.link)
-        let key = null
-        if (parent.constructor === ID) {
-          const parentItem = find(transaction.doc.store, parent)
+      if (this.raw !== null) {
+        const { type, tname, key, item } = this.raw
+        let parent = null
+        if (type !== null) {
+          const parentItem = find(transaction.doc.store, type)
           if (parentItem.constructor === Item) {
             parent = /** @type {ContentType} */ (parentItem.content).type
           } else {
             parent = null
           }
         } else {
-          parent = transaction.doc.share.get(parent)
+          parent = /** @type {AbstractType<any>} */ (transaction.doc.share.get(/** @type {string} */ (tname)))
         }
 
-        if (item.constructor === ID) {
-          item = getItemCleanStart(transaction, item)
-          if (item.length > 1) {
-            item = getItemCleanEnd(transaction, transaction.doc.store, createID(item.id.client, item.id.clock + 1))
+        let target = null
+        if (item !== null) {
+          target = getItemCleanStart(transaction, item)
+          if (target.length > 1) {
+            target = getItemCleanEnd(transaction, transaction.doc.store, createID(target.id.client, target.id.clock + 1))
           }
-        } else {
-          key = item
-          item = parent._map.get(key)
+        } else if (parent !== null) {
+          target = parent._map.get(/** @type {string} */ (key)) || null
         }
-        this.link = new WeakLink(parent, item, key)
+        const source = (parent !== null && target !== null) ? {parent: parent, item: target, key: key} : null
+        this.link = new WeakLink(source)
+        this.raw = null
       }
 
-      const link = /** @type {WeakLink<any>} */ (this.link)
-      if (link.item.constructor === Item) {
-        if (link.item.linkedBy === null) {
-            link.item.linkedBy = new Set()
+      const linked = /** @type {WeakLink<any>} */ (this.link).linkedItem()
+      if (linked !== undefined && linked.constructor === Item) {
+        if (linked.linkedBy === null) {
+          linked.linkedBy = new Set()
         }
-        link.item.linkedBy.add(link)
+        linked.linkedBy.add(/** @type {WeakLink<any>} */ (this.link))
       }
     }
     
@@ -109,11 +113,14 @@ import {
      * @param {Transaction} transaction
      */
     delete (transaction) {
-      const link = /** @type {WeakLink<any>} */ (this.link)
-      if (link.item.constructor === Item) {
-        if (link.item.linkedBy !== null) {
-          link.item.linkedBy.delete(link)
+      if (this.link !== null && this.link.source !== null) {
+        const item = this.link.source.item
+        if (item !== null && item.constructor === Item) {
+          if (item.linkedBy !== null) {
+            item.linkedBy.delete(this.link)
+          }
         }
+        this.link.source = null
       }
     }
 
@@ -127,26 +134,48 @@ import {
      * @param {number} offset
      */
     write (encoder, offset) {
-      const link = /** @type {WeakLink<any>} */ (this.link)
+      let type = null
+      let tname = null
+      let item = null
+      let key = null
       let flags = 0
-      const parentItem = link.source._item
-      if (parentItem) {
+      if (this.raw !== null) {
+        type = this.raw.type
+        tname = this.raw.tname
+        key = this.raw.key
+        item = this.raw.item
+      } else {
+        const source = /** @type {WeakLink<any>} */ (this.link).source
+        if (source !== null) {
+          if (source.parent._item !== null) {
+            type = source.parent._item.id
+          } else {
+            tname = findRootTypeKey(source.parent)
+          }
+          if (source.item !== null) {
+            item = source.item.id
+          } else {
+            key = source.key
+          }
+        }
+      }
+      
+      if (type !== null) {
         flags |= 1
       }
-      if (link.key) {
+      if (item !== null) {
         flags |= 2
       }
       encoding.writeVarUint(encoder.restEncoder, flags)
-      if (parentItem) {
-        encoder.writeLeftID(parentItem.id)
+      if (type !== null) {
+        encoder.writeLeftID(type)
       } else {
-        const ykey = findRootTypeKey(link.source)
-        encoder.writeString(ykey)
+        encoder.writeString(/** @type {string} */ (tname))
       }
-      if (link.key !== null) {
-        encoder.writeString(link.key)
+      if (item !== null) {
+        encoder.writeLeftID(item)
       } else {
-        encoder.writeLeftID(link.item.id)
+        encoder.writeString(/** @type {string} */ (key))
       }
     }
   
@@ -164,19 +193,21 @@ import {
    */
   export const readContentWeakLink = decoder => {
     const flags = decoding.readVarUint(decoder.restDecoder)
-    let parent
-    let item
+    let type = null
+    let tname = null
+    let item = null
+    let key = null
     if ((flags & 1) !== 0) {
-      parent = decoder.readLeftID()
+      type = decoder.readLeftID()
     } else {
-      parent = decoder.readString()
+      tname = decoder.readString()
     }
     if ((flags & 2) !== 0) {
-      item = decoder.readString()
-    } else {
       item = decoder.readLeftID()
+    } else {
+      key = decoder.readString()
     }
-    return new ContentLink({parent, item})
+    return new ContentLink(null, { type, tname, item, key })
   }
   
 const lengthExceeded = error.create('Length exceeded!')
@@ -191,23 +222,23 @@ const lengthExceeded = error.create('Length exceeded!')
  */
 export const arrayWeakLink = (transaction, parent, index) => {
   const marker = findMarker(parent, index)
-  let n = parent._start
+  let item = parent._start
   if (marker !== null) {
-    n = marker.p
+    item = marker.p
     index -= marker.index
   }
-  for (; n !== null; n = n.right) {
-    if (!n.deleted && n.countable) {
-      if (index < n.length) {
+  for (; item !== null; item = item.right) {
+    if (!item.deleted && item.countable) {
+      if (index < item.length) {
         if (index > 0) {
-            n = getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index))
+            item = getItemCleanStart(transaction, createID(item.id.client, item.id.clock + index))
         }
-        if (n.length > 1) {
-            n = getItemCleanEnd(transaction, transaction.doc.store, createID(n.id.client, n.id.clock + 1))
+        if (item.length > 1) {
+            item = getItemCleanEnd(transaction, transaction.doc.store, createID(item.id.client, item.id.clock + 1))
         }
-        return new WeakLink(parent, n, null)
+        return new WeakLink({parent, item, key: null})
       }
-      index -= n.length
+      index -= item.length
     }
   }
 
@@ -224,7 +255,7 @@ export const arrayWeakLink = (transaction, parent, index) => {
 export const mapWeakLink = (parent, key) => {
   const item = parent._map.get(key)
   if (item !== undefined) {
-    return new WeakLink(parent, item, key)
+    return new WeakLink({parent, item, key})
   } else {
     return undefined
   }
diff --git a/src/structs/Item.js b/src/structs/Item.js
index 3c510904..ce06345d 100644
--- a/src/structs/Item.js
+++ b/src/structs/Item.js
@@ -388,9 +388,12 @@ export class Item extends AbstractStruct {
     }
     if (this.content.constructor === ContentLink) {
       const content = /** @type {ContentLink} */ (this.content)
-      if (content.link.item.constructor === ID) {
-        if (content.link.item.client !== this.id.client) {
-          return content.link.item.client
+      if (content.raw !== null) {
+        const { type, item } = content.raw
+        if (type !== null && type.client !== this.id.client)  {
+          return type.client
+        } else if (item !== null && item.client !== this.id.client) {
+          return item.client
         }
       }
     }
diff --git a/src/types/AbstractType.js b/src/types/AbstractType.js
index 4f9830c8..9aaa95c9 100644
--- a/src/types/AbstractType.js
+++ b/src/types/AbstractType.js
@@ -670,7 +670,7 @@ export const typeListInsertGenericsAfter = (transaction, parent, referenceItem,
               left.integrate(transaction, 0)
               break
             case WeakLink:
-              left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentLink(/** @type {WeakLink<any>} */ (c)))
+              left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentLink(/** @type {WeakLink<any>} */ (c), null))
               left.integrate(transaction, 0)
               break
             default:
@@ -856,7 +856,7 @@ export const typeMapSet = (transaction, parent, key, value) => {
         content = new ContentDoc(/** @type {Doc} */ (value))
         break
       case WeakLink:
-        content = new ContentLink(/** @type {WeakLink<any>} */ (value))
+        content = new ContentLink(/** @type {WeakLink<any>} */ (value), null)
         break;
       default:
         if (value instanceof AbstractType) {
diff --git a/src/types/WeakLink.js b/src/types/WeakLink.js
index cb705a9d..2029b01c 100644
--- a/src/types/WeakLink.js
+++ b/src/types/WeakLink.js
@@ -8,14 +8,10 @@ import { typeMapGet } from "./AbstractType.js"
  */
 export class WeakLink {
   /**
-    * @param {AbstractType<any>} source
-    * @param {Item|GC} item
-    * @param {string|null} key
+    * @param {{parent:AbstractType<any>,item:Item|GC|null,key:string|null}|null} source
     */
-  constructor(source, item, key) {
+  constructor(source) {
     this.source = source
-    this.item = item
-    this.key = key
   }
   
   /**
@@ -24,14 +20,37 @@ export class WeakLink {
    * @return {T|undefined}
    */
   deref() {
-    if (this.key) {
-      return /** @type {T|undefined} */ (typeMapGet(this.source, this.key))
+    const item = this.linkedItem()
+    if (item !== undefined && !item.deleted) {
+      return /** @type {Item} */ (item).content.getContent()[0]
     } else {
-      if (this.item.constructor === Item) {
-        return this.item.content.getContent()[0]
-      } else {
-        return undefined
-      }
+      return undefined
     }
   }
+
+  /**
+   * Returns currently linked item to an underlying value existing somewhere on in the document.
+   * 
+   * @return {Item|GC|undefined}
+   */
+  linkedItem() {
+    if (this.source !== null) {
+      const source = this.source
+      if (source.key !== null) {
+        return source.parent._map.get(source.key)
+      } else if (source.item !== null && !source.item.deleted) {
+        return source.item
+      }
+    }
+    return undefined
+  }
+
+  /**
+   * Checks if a linked content source has been deleted.
+   * 
+   * @return {boolean}
+   */
+  get deleted() {
+    return this.source === null || this.source.item === null || this.source.item.deleted
+  }
 }
diff --git a/tests/weakLinks.tests.js b/tests/weakLinks.tests.js
index 90a81ecb..c5fd4f25 100644
--- a/tests/weakLinks.tests.js
+++ b/tests/weakLinks.tests.js
@@ -64,8 +64,6 @@ export const testUpdate = tc => {
   l1 = /** @type {Y.Map<any>} */ (link1.deref())
   l0 = /** @type {Y.Map<any>} */ (link0.deref())
   t.compare(l1.get('a2'), l0.get('a2'))
-
-  compare(users)
 }
 
 /**
@@ -78,19 +76,23 @@ export const testDeleteWeakLink = tc => {
   map0.set('b', link0)
 
   testConnector.flushAllMessages()
+  
   const link1 = /** @type {Y.WeakLink<Y.Map>} */ map1.get('b')
+  const l1 = /** @type {Y.Map<any>} */ (link1.deref())
   const l0 = /** @type {Y.Map<any>} */ (link0.deref())
-  t.compare(link1.ref.get('a1'), l0.get('a1'))
+  t.compare(l1.get('a1'), l0.get('a1'))
+  t.compare(link0.deleted, false)
+  t.compare(link1.deleted, false)
 
   map1.delete('b') // delete links
 
   testConnector.flushAllMessages()
 
   // since links have been deleted, they no longer refer to any content
+  t.compare(link0.deleted, true)
+  t.compare(link1.deleted, true)
   t.compare(link0.deref(), undefined)
   t.compare(link1.deref(), undefined)
-
-  compare(users)
 }
 
 /**
@@ -106,6 +108,8 @@ export const testDeleteSource = tc => {
   const link1 = /** @type {Y.WeakLink<Y.Map<any>>} */ (map1.get('b'))
   let l1 = /** @type {Y.Map<any>} */ (link1.deref())
   let l0 = /** @type {Y.Map<any>} */ (link0.deref())
+  t.compare(link0.deleted, false)
+  t.compare(link1.deleted, false)
   t.compare(l1.get('a1'), l0.get('a1'))
 
   map1.delete('a') // delete source of the link
@@ -113,10 +117,10 @@ export const testDeleteSource = tc => {
   testConnector.flushAllMessages()
 
   // since source have been deleted, links no longer refer to any content
+  t.compare(link0.deleted, true)
+  t.compare(link1.deleted, true)
   t.compare(link0.deref(), undefined)
   t.compare(link1.deref(), undefined)
-
-  compare(users)
 }
 
 /**