diff --git a/app/models/user_first.rb b/app/models/user_first.rb
deleted file mode 100644
index 80e875b7e..000000000
--- a/app/models/user_first.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class UserFirst < ActiveRecord::Base
-
-  def self.types
-    @types ||= Enum.new(used_emoji: 1,
-                        mentioned_user: 2 #unused now
-                       )
-  end
-
-  def self.create_for(user_id, type, post_id=nil)
-    # the usual case will be that it is already in table, don't try to insert
-    return false if UserFirst.exists?(user_id: user_id, first_type: types[type])
-
-    create!(user_id: user_id, first_type: types[type], post_id: post_id)
-    true
-  rescue PG::UniqueViolation, ActiveRecord::RecordNotUnique
-    # Violating the index just means the user already did it
-    false
-  end
-end
diff --git a/db/fixtures/006_badges.rb b/db/fixtures/006_badges.rb
index 9de13c996..3f02e0fe6 100644
--- a/db/fixtures/006_badges.rb
+++ b/db/fixtures/006_badges.rb
@@ -379,7 +379,7 @@ Badge.seed do |b|
   b.multiple_grant = false
   b.target_posts = true
   b.show_posts = true
-  b.query = BadgeQueries.has_user_first(:used_emoji)
+  b.query = nil
   b.badge_grouping_id = BadgeGrouping::GettingStarted
   b.default_badge_grouping_id = BadgeGrouping::GettingStarted
   b.trigger = Badge::Trigger::PostProcessed
diff --git a/db/migrate/20160407160756_remove_user_firsts.rb b/db/migrate/20160407160756_remove_user_firsts.rb
new file mode 100644
index 000000000..2fda4c75f
--- /dev/null
+++ b/db/migrate/20160407160756_remove_user_firsts.rb
@@ -0,0 +1,5 @@
+class RemoveUserFirsts < ActiveRecord::Migration
+  def up
+    drop_table :user_firsts
+  end
+end
diff --git a/lib/badge_queries.rb b/lib/badge_queries.rb
index 8f32017b1..765c07375 100644
--- a/lib/badge_queries.rb
+++ b/lib/badge_queries.rb
@@ -246,13 +246,4 @@ SQL
     SQL
   end
 
-  def self.has_user_first(type)
-    <<SQL
-  SELECT uf.user_id, uf.post_id, uf.created_at AS granted_at
-  FROM user_firsts AS uf
-  WHERE (:backfill OR uf.user_id IN (:user_ids))
-    AND uf.first_type = #{UserFirst.types[type]}
-SQL
-  end
-
 end
diff --git a/lib/cooked_post_processor.rb b/lib/cooked_post_processor.rb
index 6b730d719..d0f939ffa 100644
--- a/lib/cooked_post_processor.rb
+++ b/lib/cooked_post_processor.rb
@@ -28,7 +28,7 @@ class CookedPostProcessor
       post_process_oneboxes
       optimize_urls
       pull_hotlinked_images(bypass_bump)
-      create_firsts
+      grant_badges
     end
   end
 
@@ -36,17 +36,11 @@ class CookedPostProcessor
     (@doc.css("img.emoji") - @doc.css(".quote img")).size > 0
   end
 
-  def create_firsts
+  def grant_badges
     return unless Guardian.new.can_see?(@post)
 
-    created = false
-
     if has_emoji?
-      created |= UserFirst.create_for(@post.user_id, :used_emoji, @post.id)
-    end
-
-    if created
-      BadgeGranter.queue_badge_grant(Badge::Trigger::PostProcessed, user: @post.user)
+      BadgeGranter.grant(Badge.find(Badge::FirstEmoji), @post.user)
     end
   end
 
diff --git a/spec/components/cooked_post_processor_spec.rb b/spec/components/cooked_post_processor_spec.rb
index 800713400..b83a76658 100644
--- a/spec/components/cooked_post_processor_spec.rb
+++ b/spec/components/cooked_post_processor_spec.rb
@@ -478,4 +478,26 @@ describe CookedPostProcessor do
 
   end
 
+  context "grant badges" do
+    context "emoji inside a quote" do
+      let(:post) { Fabricate(:post, raw: "time to eat some sweet [quote]:candy:[/quote] mmmm") }
+      let(:cpp) { CookedPostProcessor.new(post) }
+
+      it "doesn't award a badge when the emoji is in a quote" do
+        cpp.grant_badges
+        expect(post.user.user_badges.where(badge_id: Badge::FirstEmoji).exists?).to eq(false)
+      end
+    end
+
+    context "emoji in the text" do
+      let(:post) { Fabricate(:post, raw: "time to eat some sweet :candy: mmmm") }
+      let(:cpp) { CookedPostProcessor.new(post) }
+
+      it "awards a badge for using an emoji" do
+        cpp.grant_badges
+        expect(post.user.user_badges.where(badge_id: Badge::FirstEmoji).exists?).to eq(true)
+      end
+    end
+  end
+
 end
diff --git a/spec/models/user_firsts_spec.rb b/spec/models/user_firsts_spec.rb
deleted file mode 100644
index c93d49103..000000000
--- a/spec/models/user_firsts_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require 'rails_helper'
-
-describe UserFirst do
-
-  let(:user) { Fabricate(:user) }
-
-  context "#create_for" do
-    it "doesn't raise an error on duplicate" do
-      expect(UserFirst.create_for(user.id, :used_emoji)).to eq(true)
-      expect(UserFirst.create_for(user.id, :used_emoji)).to eq(false)
-    end
-  end
-
-  context "emoji" do
-    it "logs a user first" do
-      post = PostCreator.create(user, title: "this topic is about candy", raw: "time to eat some sweet :candy: mmmm")
-
-      uf = UserFirst.where(user_id: user.id, first_type: UserFirst.types[:used_emoji]).first
-      expect(uf).to be_present
-      expect(uf.post_id).to eq(post.id)
-    end
-
-    it "doesn't log a user first when in a quote" do
-      PostCreator.create(user,
-                         title: "this topic is about candy",
-                         raw: "time to eat some sweet [quote]:candy:[/quote] mmmm")
-
-      uf = UserFirst.where(user_id: user.id, first_type: UserFirst.types[:used_emoji]).first
-      expect(uf).to be_blank
-    end
-
-  end
-
-  context "privacy" do
-    let(:codinghorror) { Fabricate(:codinghorror) }
-
-    it "doesn't create the userfirst on private posts" do
-      PostCreator.create(user,
-                         archetype: Archetype.private_message,
-                         target_usernames: ['codinghorror'],
-                         title: "this topic is about candy",
-                         raw: "time to eat some sweet :candy: mmmm")
-
-      uf = UserFirst.where(user_id: user.id, first_type: UserFirst.types[:used_emoji]).first
-      expect(uf).to be_blank
-    end
-  end
-end