diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index 301cfd134..b5aadfd17 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -80,9 +80,8 @@ defmodule Pleroma.Notification do
   end
 
   def clear(user) do
-    query = from(n in Notification, where: n.user_id == ^user.id)
-
-    Repo.delete_all(query)
+    from(n in Notification, where: n.user_id == ^user.id)
+    |> Repo.delete_all()
   end
 
   def dismiss(%{id: user_id} = _user, id) do
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index cc4a2181a..e2b648727 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -4,7 +4,7 @@
 
 defmodule Pleroma.Object do
   use Ecto.Schema
-  alias Pleroma.{Repo, Object, User, Activity}
+  alias Pleroma.{Repo, Object, User, Activity, ObjectTombstone}
   import Ecto.{Query, Changeset}
 
   schema "objects" do
@@ -66,8 +66,25 @@ defmodule Pleroma.Object do
     Object.change(%Object{}, %{data: %{"id" => context}})
   end
 
+  def make_tombstone(%Object{data: %{"id" => id, "type" => type}}, deleted \\ DateTime.utc_now()) do
+    %ObjectTombstone{
+      id: id,
+      formerType: type,
+      deleted: deleted
+    }
+    |> Map.from_struct()
+  end
+
+  def swap_object_with_tombstone(object) do
+    tombstone = make_tombstone(object)
+
+    object
+    |> Object.change(%{data: tombstone})
+    |> Repo.update()
+  end
+
   def delete(%Object{data: %{"id" => id}} = object) do
-    with Repo.delete(object),
+    with {:ok, _obj} = swap_object_with_tombstone(object),
          Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),
          {:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do
       {:ok, object}
diff --git a/lib/pleroma/object_tombstone.ex b/lib/pleroma/object_tombstone.ex
new file mode 100644
index 000000000..64d836d3e
--- /dev/null
+++ b/lib/pleroma/object_tombstone.ex
@@ -0,0 +1,4 @@
+defmodule Pleroma.ObjectTombstone do
+  @enforce_keys [:id, :formerType, :deleted]
+  defstruct [:id, :formerType, :deleted, type: "Tombstone"]
+end
diff --git a/test/activity_test.exs b/test/activity_test.exs
index cf27fbbc5..36c718869 100644
--- a/test/activity_test.exs
+++ b/test/activity_test.exs
@@ -4,18 +4,19 @@
 
 defmodule Pleroma.ActivityTest do
   use Pleroma.DataCase
+  alias Pleroma.Activity
   import Pleroma.Factory
 
   test "returns an activity by it's AP id" do
     activity = insert(:note_activity)
-    found_activity = Pleroma.Activity.get_by_ap_id(activity.data["id"])
+    found_activity = Activity.get_by_ap_id(activity.data["id"])
 
     assert activity == found_activity
   end
 
   test "returns activities by it's objects AP ids" do
     activity = insert(:note_activity)
-    [found_activity] = Pleroma.Activity.all_by_object_ap_id(activity.data["object"]["id"])
+    [found_activity] = Activity.all_by_object_ap_id(activity.data["object"]["id"])
 
     assert activity == found_activity
   end
@@ -23,8 +24,7 @@ defmodule Pleroma.ActivityTest do
   test "returns the activity that created an object" do
     activity = insert(:note_activity)
 
-    found_activity =
-      Pleroma.Activity.get_create_activity_by_object_ap_id(activity.data["object"]["id"])
+    found_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"]["id"])
 
     assert activity == found_activity
   end
diff --git a/test/object_test.exs b/test/object_test.exs
index 0effb9505..72194975d 100644
--- a/test/object_test.exs
+++ b/test/object_test.exs
@@ -36,6 +36,8 @@ defmodule Pleroma.ObjectTest do
       found_object = Object.get_by_ap_id(object.data["id"])
 
       refute object == found_object
+
+      assert found_object.data["type"] == "Tombstone"
     end
 
     test "ensures cache is cleared for the object" do
@@ -51,6 +53,8 @@ defmodule Pleroma.ObjectTest do
       cached_object = Object.get_cached_by_ap_id(object.data["id"])
 
       refute object == cached_object
+
+      assert cached_object.data["type"] == "Tombstone"
     end
   end
 end
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index f7c66038d..7bccd7500 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -492,7 +492,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
       assert Repo.get(Activity, delete.id) != nil
 
-      assert Repo.get(Object, object.id) == nil
+      assert Repo.get(Object, object.id).data["type"] == "Tombstone"
     end
   end
 
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 1737a5ebe..0136acf8c 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -296,7 +296,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       assert %{} = json_response(conn, 200)
 
-      assert Repo.get(Activity, activity.id) == nil
+      refute Repo.get(Activity, activity.id)
     end
 
     test "when you didn't create it", %{conn: conn} do
diff --git a/test/web/ostatus/incoming_documents/delete_handling_test.exs b/test/web/ostatus/incoming_documents/delete_handling_test.exs
index 1e041e5b0..c8fbff6cc 100644
--- a/test/web/ostatus/incoming_documents/delete_handling_test.exs
+++ b/test/web/ostatus/incoming_documents/delete_handling_test.exs
@@ -25,7 +25,7 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
 
       refute Repo.get(Activity, note.id)
       refute Repo.get(Activity, like.id)
-      refute Object.get_by_ap_id(note.data["object"]["id"])
+      assert Object.get_by_ap_id(note.data["object"]["id"]).data["type"] == "Tombstone"
       assert Repo.get(Activity, second_note.id)
       assert Object.get_by_ap_id(second_note.data["object"]["id"])
 
diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs
index 6b535a1a9..995cc00d6 100644
--- a/test/web/ostatus/ostatus_controller_test.exs
+++ b/test/web/ostatus/ostatus_controller_test.exs
@@ -5,7 +5,7 @@
 defmodule Pleroma.Web.OStatus.OStatusControllerTest do
   use Pleroma.Web.ConnCase
   import Pleroma.Factory
-  alias Pleroma.{User, Repo}
+  alias Pleroma.{User, Repo, Object}
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.OStatus.ActivityRepresenter
 
@@ -114,6 +114,22 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
     |> response(404)
   end
 
+  test "404s on deleted objects", %{conn: conn} do
+    note_activity = insert(:note_activity)
+    [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["object"]["id"]))
+    object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+
+    conn
+    |> get("/objects/#{uuid}")
+    |> response(200)
+
+    Object.delete(object)
+
+    conn
+    |> get("/objects/#{uuid}")
+    |> response(404)
+  end
+
   test "gets an activity", %{conn: conn} do
     note_activity = insert(:note_activity)
     [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))