diff --git a/app/assets/javascripts/admin/components/admin-user-field-item.js.es6 b/app/assets/javascripts/admin/components/admin-user-field-item.js.es6
index f4d93d9c726..337b10557c9 100644
--- a/app/assets/javascripts/admin/components/admin-user-field-item.js.es6
+++ b/app/assets/javascripts/admin/components/admin-user-field-item.js.es6
@@ -10,6 +10,10 @@ export default Ember.Component.extend(bufferedProperty('userField'), {
     return I18n.t('admin.user_fields.description');
   }.property(),
 
+  bufferedFieldType: function() {
+    return UserField.fieldTypeById(this.get('buffered.field_type'));
+  }.property('buffered.field_type'),
+
   _focusOnEdit: function() {
     if (this.get('editing')) {
       Ember.run.scheduleOnce('afterRender', this, '_focusName');
@@ -42,7 +46,14 @@ export default Ember.Component.extend(bufferedProperty('userField'), {
   actions: {
     save() {
       const self = this;
-      const attrs = this.get('buffered').getProperties('name', 'description', 'field_type', 'editable', 'required', 'show_on_profile');
+      const buffered = this.get('buffered');
+      const attrs = buffered.getProperties('name',
+                                           'description',
+                                           'field_type',
+                                           'editable',
+                                           'required',
+                                           'show_on_profile',
+                                           'options');
 
       this.get('userField').save(attrs).then(function(res) {
         self.set('userField.id', res.user_field.id);
diff --git a/app/assets/javascripts/admin/components/value-list.js.es6 b/app/assets/javascripts/admin/components/value-list.js.es6
index c995097a9d2..a7704f254ec 100644
--- a/app/assets/javascripts/admin/components/value-list.js.es6
+++ b/app/assets/javascripts/admin/components/value-list.js.es6
@@ -3,11 +3,19 @@ export default Ember.Component.extend({
 
   _setupCollection: function() {
     const values = this.get('values');
-    this.set('collection', (values && values.length) ? values.split("\n") : []);
+    if (this.get('inputType') === "array") {
+      this.set('collection', values || []);
+    } else {
+      this.set('collection', (values && values.length) ? values.split("\n") : []);
+    }
   }.on('init').observes('values'),
 
   _collectionChanged: function() {
-    this.set('values', this.get('collection').join("\n"));
+    if (this.get('inputType') === "array") {
+      this.set('values', this.get('collection'));
+    } else {
+      this.set('values', this.get('collection').join("\n"));
+    }
   }.observes('collection.@each'),
 
   inputInvalid: Ember.computed.empty('newValue'),
diff --git a/app/assets/javascripts/admin/models/user-field.js.es6 b/app/assets/javascripts/admin/models/user-field.js.es6
index e5c3348efd0..35ee8e0bde9 100644
--- a/app/assets/javascripts/admin/models/user-field.js.es6
+++ b/app/assets/javascripts/admin/models/user-field.js.es6
@@ -1,8 +1,9 @@
-var UserField = Ember.Object.extend({
-  destroy: function() {
-    var self = this;
+const UserField = Ember.Object.extend({
+
+  destroy() {
+    const self = this;
     return new Ember.RSVP.Promise(function(resolve) {
-      var id = self.get('id');
+      const id = self.get('id');
       if (id) {
         return Discourse.ajax("/admin/customize/user_fields/" + id, { type: 'DELETE' }).then(function() {
           resolve();
@@ -12,8 +13,8 @@ var UserField = Ember.Object.extend({
     });
   },
 
-  save: function(attrs) {
-    var id = this.get('id');
+  save(attrs) {
+    const id = this.get('id');
     if (!id) {
       return Discourse.ajax("/admin/customize/user_fields", {
         type: "POST",
@@ -28,8 +29,12 @@ var UserField = Ember.Object.extend({
   }
 });
 
+const UserFieldType = Ember.Object.extend({
+  name: Discourse.computed.i18n('id', 'admin.user_fields.field_types.%@')
+});
+
 UserField.reopenClass({
-  findAll: function() {
+  findAll() {
     return Discourse.ajax("/admin/customize/user_fields").then(function(result) {
       return result.user_fields.map(function(uf) {
         return UserField.create(uf);
@@ -37,18 +42,19 @@ UserField.reopenClass({
     });
   },
 
-  fieldTypes: function() {
+  fieldTypes() {
     if (!this._fieldTypes) {
       this._fieldTypes = [
-        Ember.Object.create({id: 'text', name: I18n.t('admin.user_fields.field_types.text') }),
-        Ember.Object.create({id: 'confirm', name: I18n.t('admin.user_fields.field_types.confirm') })
+        UserFieldType.create({ id: 'text' }),
+        UserFieldType.create({ id: 'confirm' }),
+        UserFieldType.create({ id: 'dropdown', hasOptions: true })
       ];
     }
 
     return this._fieldTypes;
   },
 
-  fieldTypeById: function(id) {
+  fieldTypeById(id) {
     return this.fieldTypes().findBy('id', id);
   }
 });
diff --git a/app/assets/javascripts/admin/templates/components/admin-form-row.hbs b/app/assets/javascripts/admin/templates/components/admin-form-row.hbs
index d9ea5d58546..aee95b67012 100644
--- a/app/assets/javascripts/admin/templates/components/admin-form-row.hbs
+++ b/app/assets/javascripts/admin/templates/components/admin-form-row.hbs
@@ -1,11 +1,11 @@
-<div class='form-element-desc'>
+<div class='form-element label-area'>
   {{#if label}}
     <label>{{i18n label}}</label>
   {{else}}
     &nbsp;
   {{/if}}
 </div>
-<div class='form-element'>
+<div class='form-element input-area'>
   {{#if wrapLabel}}
     <label>{{yield}}</label>
   {{else}}
diff --git a/app/assets/javascripts/admin/templates/components/admin-user-field-item.hbs b/app/assets/javascripts/admin/templates/components/admin-user-field-item.hbs
index a5754befaef..4bb52c9e61a 100644
--- a/app/assets/javascripts/admin/templates/components/admin-user-field-item.hbs
+++ b/app/assets/javascripts/admin/templates/components/admin-user-field-item.hbs
@@ -11,6 +11,12 @@
     {{input value=buffered.description class="user-field-desc"}}
   {{/admin-form-row}}
 
+  {{#if bufferedFieldType.hasOptions}}
+    {{#admin-form-row label="admin.user_fields.options"}}
+      {{value-list values=buffered.options inputType="array"}}
+    {{/admin-form-row}}
+  {{/if}}
+
   {{#admin-form-row wrapLabel="true"}}
     {{input type="checkbox" checked=buffered.editable}} {{i18n 'admin.user_fields.editable.title'}}
   {{/admin-form-row}}
diff --git a/app/assets/javascripts/discourse/components/combo-box.js.es6 b/app/assets/javascripts/discourse/components/combo-box.js.es6
index 5fdd914e825..d74410e89b5 100644
--- a/app/assets/javascripts/discourse/components/combo-box.js.es6
+++ b/app/assets/javascripts/discourse/components/combo-box.js.es6
@@ -3,8 +3,9 @@ export default Ember.Component.extend({
   attributeBindings: ['tabindex'],
   classNames: ['combobox'],
   valueAttribute: 'id',
+  nameProperty: 'name',
 
-  buildData(o) {
+  _buildData(o) {
     let result = "";
     if (this.resultAttributes) {
       this.resultAttributes.forEach(function(a) {
@@ -14,19 +15,15 @@ export default Ember.Component.extend({
     return result;
   },
 
-  realNameProperty: function() {
-    return this.get('nameProperty') || 'name';
-  }.property('nameProperty'),
-
   render(buffer) {
-    const nameProperty = this.get('realNameProperty'),
-        none = this.get('none');
+    const nameProperty = this.get('nameProperty');
+    const none = this.get('none');
 
     // Add none option if required
     if (typeof none === "string") {
       buffer.push('<option value="">' + I18n.t(none) + "</option>");
     } else if (typeof none === "object") {
-      buffer.push("<option value=\"\" " + this.buildData(none) + ">" + Em.get(none, nameProperty) + "</option>");
+      buffer.push("<option value=\"\" " + this._buildData(none) + ">" + Em.get(none, nameProperty) + "</option>");
     }
 
     let selected = this.get('value');
@@ -35,18 +32,20 @@ export default Ember.Component.extend({
     if (this.get('content')) {
       const self = this;
       this.get('content').forEach(function(o) {
-        let val = o[self.get('valueAttribute')];
+        let val = o[self.get('valueAttribute')] || o;
         if (!Em.isNone(val)) { val = val.toString(); }
 
         const selectedText = (val === selected) ? "selected" : "";
-        buffer.push("<option " + selectedText + " value=\"" + val + "\" " + self.buildData(o) + ">" + Handlebars.Utils.escapeExpression(Em.get(o, nameProperty)) + "</option>");
+        const name = Ember.get(o, nameProperty) || o;
+        buffer.push("<option " + selectedText + " value=\"" + val + "\" " + self._buildData(o) + ">" + Handlebars.Utils.escapeExpression(name) + "</option>");
       });
     }
   },
 
   valueChanged: function() {
     const $combo = this.$(),
-        val = this.get('value');
+          val = this.get('value');
+
     if (val !== undefined && val !== null) {
       $combo.select2('val', val.toString());
     } else {
@@ -54,13 +53,11 @@ export default Ember.Component.extend({
     }
   }.observes('value'),
 
-  contentChanged: function() {
+  _rerenderOnChange: function() {
     this.rerender();
   }.observes('content.@each'),
 
   _initializeCombo: function() {
-    const $elem = this.$(),
-        self = this;
 
     // Workaround for https://github.com/emberjs/ember.js/issues/9813
     // Can be removed when fixed. Without it, the wrong option is selected
@@ -70,12 +67,14 @@ export default Ember.Component.extend({
 
     // observer for item names changing (optional)
     if (this.get('nameChanges')) {
-      this.addObserver('content.@each.' + this.get('realNameProperty'), this.rerender);
+      this.addObserver('content.@each.' + this.get('nameProperty'), this.rerender);
     }
 
+    const $elem = this.$();
     $elem.select2({formatResult: this.comboTemplate, minimumResultsForSearch: 5, width: 'resolve'});
 
     const castInteger = this.get('castInteger');
+    const self = this;
     $elem.on("change", function (e) {
       let val = $(e.target).val();
       if (val && val.length && castInteger) {
diff --git a/app/assets/javascripts/discourse/components/user-field.js.es6 b/app/assets/javascripts/discourse/components/user-field.js.es6
index a1c6f56b4dd..625067622e4 100644
--- a/app/assets/javascripts/discourse/components/user-field.js.es6
+++ b/app/assets/javascripts/discourse/components/user-field.js.es6
@@ -1,6 +1,10 @@
 export default Ember.Component.extend({
   classNameBindings: [':user-field', 'field.field_type'],
-  layoutName: function() {
-    return "components/user-fields/" + this.get('field.field_type');
-  }.property('field.field_type')
+  layoutName: Discourse.computed.fmt('field.field_type', 'components/user-fields/%@'),
+
+  noneLabel: function() {
+    if (!this.get('field.required')) {
+      return 'user_fields.none';
+    }
+  }.property('field.required')
 });
diff --git a/app/assets/javascripts/discourse/templates/components/user-fields/dropdown.hbs b/app/assets/javascripts/discourse/templates/components/user-fields/dropdown.hbs
new file mode 100644
index 00000000000..9c5d37ec0bc
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/user-fields/dropdown.hbs
@@ -0,0 +1,6 @@
+<label>{{{field.name}}}</label>
+<div class='controls'>
+  {{combo-box content=field.options value=value none=noneLabel}}
+  {{#if field.required}}<span class='required'>*</span>{{/if}}
+  <p>{{{field.description}}}</p>
+</div>
diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss
index bcd9a529ebe..0c572b5311c 100644
--- a/app/assets/stylesheets/common/admin/admin_base.scss
+++ b/app/assets/stylesheets/common/admin/admin_base.scss
@@ -1437,15 +1437,24 @@ tr.not-activated {
 
     .form-element, .form-element-desc {
       float: left;
-      width: 25%;
-      height: 30px;
+      min-height: 30px;
       padding: 0.25em 0;
-    }
 
-    .form-element-desc label {
-      margin: 0.5em 1em 0 0;
-      text-align: right;
-      font-weight: bold;
+      &.input-area {
+        width: 75%;
+        input[type=text] {
+          width: 50%;
+        }
+      }
+
+      &.label-area {
+        width: 25%;
+        label {
+          margin: 0.5em 1em 0 0;
+          text-align: right;
+          font-weight: bold;
+        }
+      }
     }
 
     .controls {
diff --git a/app/controllers/admin/user_fields_controller.rb b/app/controllers/admin/user_fields_controller.rb
index e5e8c9c3a9e..6770d67bda0 100644
--- a/app/controllers/admin/user_fields_controller.rb
+++ b/app/controllers/admin/user_fields_controller.rb
@@ -7,13 +7,16 @@ class Admin::UserFieldsController < Admin::AdminController
   def create
     field = UserField.new(params.require(:user_field).permit(*Admin::UserFieldsController.columns))
     field.required = params[:required] == "true"
+    fetch_options(field)
+
     json_result(field, serializer: UserFieldSerializer) do
       field.save
     end
   end
 
   def index
-    render_serialized(UserField.all, UserFieldSerializer, root: 'user_fields')
+    user_fields = UserField.all.includes(:user_field_options)
+    render_serialized(user_fields, UserFieldSerializer, root: 'user_fields')
   end
 
   def update
@@ -24,6 +27,8 @@ class Admin::UserFieldsController < Admin::AdminController
     Admin::UserFieldsController.columns.each do |col|
       field.send("#{col}=", field_params[col] || false)
     end
+    UserFieldOption.where(user_field_id: field.id).delete_all
+    fetch_options(field)
 
     json_result(field, serializer: UserFieldSerializer) do
       field.save
@@ -36,5 +41,14 @@ class Admin::UserFieldsController < Admin::AdminController
     render nothing: true
   end
 
+
+  protected
+
+    def fetch_options(field)
+      options = params[:user_field][:options]
+      if options.present?
+        field.user_field_options_attributes = options.map {|o| {value: o} }.uniq
+      end
+    end
 end
 
diff --git a/app/models/user_field.rb b/app/models/user_field.rb
index 648163326a0..e0607950984 100644
--- a/app/models/user_field.rb
+++ b/app/models/user_field.rb
@@ -1,5 +1,7 @@
 class UserField < ActiveRecord::Base
   validates_presence_of :name, :description, :field_type
+  has_many :user_field_options, dependent: :destroy
+  accepts_nested_attributes_for :user_field_options
 
   def self.max_length
     2048
diff --git a/app/models/user_field_option.rb b/app/models/user_field_option.rb
new file mode 100644
index 00000000000..b603fcaea5a
--- /dev/null
+++ b/app/models/user_field_option.rb
@@ -0,0 +1,2 @@
+class UserFieldOption < ActiveRecord::Base
+end
diff --git a/app/serializers/user_field_serializer.rb b/app/serializers/user_field_serializer.rb
index 8638b2c04d9..0c8f6f721a4 100644
--- a/app/serializers/user_field_serializer.rb
+++ b/app/serializers/user_field_serializer.rb
@@ -5,5 +5,14 @@ class UserFieldSerializer < ApplicationSerializer
              :field_type,
              :editable,
              :required,
-             :show_on_profile
+             :show_on_profile,
+             :options
+
+  def options
+    object.user_field_options.pluck(:value)
+  end
+
+  def include_options?
+    options.present?
+  end
 end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 21f6223678a..d8da64bb3d8 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -388,6 +388,9 @@ en:
       post_count: "# posts"
       confirm_delete_other_accounts: "Are you sure you want to delete these accounts?"
 
+    user_fields:
+      none: "(select an option)"
+
     user:
       said: "{{username}}:"
       profile: "Profile"
@@ -2331,6 +2334,7 @@ en:
         delete: "Delete"
         cancel: "Cancel"
         delete_confirm: "Are you sure you want to delete that user field?"
+        options: "Options"
         required:
           title: "Required at signup?"
           enabled: "required"
@@ -2347,6 +2351,7 @@ en:
         field_types:
           text: 'Text Field'
           confirm: 'Confirmation'
+          dropdown: "Dropdown"
 
       site_text:
         none: "Choose a type of content to begin editing."
diff --git a/db/migrate/20150727193414_create_user_field_options.rb b/db/migrate/20150727193414_create_user_field_options.rb
new file mode 100644
index 00000000000..189025a96e1
--- /dev/null
+++ b/db/migrate/20150727193414_create_user_field_options.rb
@@ -0,0 +1,9 @@
+class CreateUserFieldOptions < ActiveRecord::Migration
+  def change
+    create_table :user_field_options do |t|
+      t.references :user_field, null: false
+      t.string :value, null: false
+      t.timestamps
+    end
+  end
+end
diff --git a/spec/controllers/admin/user_fields_controller_spec.rb b/spec/controllers/admin/user_fields_controller_spec.rb
index 6b173cb91dd..bd6bd517dba 100644
--- a/spec/controllers/admin/user_fields_controller_spec.rb
+++ b/spec/controllers/admin/user_fields_controller_spec.rb
@@ -16,6 +16,18 @@ describe Admin::UserFieldsController do
           expect(response).to be_success
         }.to change(UserField, :count).by(1)
       end
+
+      it "creates a user field with options" do
+        expect {
+          xhr :post, :create, {user_field: {name: 'hello',
+                                            description: 'hello desc',
+                                            field_type: 'dropdown',
+                                            options: ['a', 'b', 'c']} }
+          expect(response).to be_success
+        }.to change(UserField, :count).by(1)
+
+        expect(UserFieldOption.count).to eq(3)
+      end
     end
 
     context '.index' do
@@ -50,6 +62,18 @@ describe Admin::UserFieldsController do
         expect(user_field.name).to eq('fraggle')
         expect(user_field.field_type).to eq('confirm')
       end
+
+      it "updates the user field options" do
+        xhr :put, :update, id: user_field.id, user_field: {name: 'fraggle',
+                                                           field_type: 'dropdown',
+                                                           description: 'muppet',
+                                                           options: ['hello', 'hello', 'world']}
+        expect(response).to be_success
+        user_field.reload
+        expect(user_field.name).to eq('fraggle')
+        expect(user_field.field_type).to eq('dropdown')
+        expect(user_field.user_field_options.size).to eq(2)
+      end
     end
   end
 
diff --git a/test/javascripts/components/combo-box-test.js.es6 b/test/javascripts/components/combo-box-test.js.es6
new file mode 100644
index 00000000000..4badfcd1a61
--- /dev/null
+++ b/test/javascripts/components/combo-box-test.js.es6
@@ -0,0 +1,45 @@
+import componentTest from 'helpers/component-test';
+moduleForComponent('combo-box', {integration: true});
+
+componentTest('with objects', {
+  template: '{{combo-box content=items value=value}}',
+  setup() {
+    this.set('items', [{id: 1, name: 'hello'}, {id: 2, name: 'world'}]);
+  },
+
+  test(assert) {
+    assert.equal(this.get('value'), 1);
+    assert.ok(this.$('.combobox').length);
+    assert.equal(this.$("select option[value='1']").text(), 'hello');
+    assert.equal(this.$("select option[value='2']").text(), 'world');
+  }
+});
+
+componentTest('with an array', {
+  template: '{{combo-box content=items value=value}}',
+  setup() {
+    this.set('items', ['evil', 'trout', 'hat']);
+  },
+
+  test(assert) {
+    assert.equal(this.get('value'), 'evil');
+    assert.ok(this.$('.combobox').length);
+    assert.equal(this.$("select option[value='evil']").text(), 'evil');
+    assert.equal(this.$("select option[value='trout']").text(), 'trout');
+  }
+});
+
+componentTest('with none', {
+  template: '{{combo-box content=items none="test.none" value=value}}',
+  setup() {
+    I18n.translations[I18n.locale].js.test = {none: 'none'};
+    this.set('items', ['evil', 'trout', 'hat']);
+  },
+
+  test(assert) {
+    assert.equal(this.$("select option:eq(0)").text(), 'none');
+    assert.equal(this.$("select option:eq(0)").val(), '');
+    assert.equal(this.$("select option:eq(1)").text(), 'evil');
+    assert.equal(this.$("select option:eq(2)").text(), 'trout');
+  }
+});
diff --git a/test/javascripts/components/value-list-test.js.es6 b/test/javascripts/components/value-list-test.js.es6
index df838f95421..7bb9599eece 100644
--- a/test/javascripts/components/value-list-test.js.es6
+++ b/test/javascripts/components/value-list-test.js.es6
@@ -2,13 +2,11 @@ import componentTest from 'helpers/component-test';
 moduleForComponent('value-list', {integration: true});
 
 componentTest('functionality', {
-  template: '{{value-list value=values}}',
-  test: function(assert) {
-    andThen(() => {
-      assert.ok(this.$('.values .value').length === 0, 'it has no values');
-      assert.ok(this.$('input').length, 'it renders the input');
-      assert.ok(this.$('.btn-primary[disabled]').length, 'it is disabled with no value');
-    });
+  template: '{{value-list values=values inputType="array"}}',
+  test(assert) {
+    assert.ok(this.$('.values .value').length === 0, 'it has no values');
+    assert.ok(this.$('input').length, 'it renders the input');
+    assert.ok(this.$('.btn-primary[disabled]').length, 'it is disabled with no value');
 
     fillIn('input', 'eviltrout');
     andThen(() => {
@@ -17,9 +15,10 @@ componentTest('functionality', {
 
     click('.btn-primary');
     andThen(() => {
-      assert.ok(this.$('.values .value').length === 1, 'it adds the value');
-      assert.ok(this.$('input').val() === '', 'it clears the input');
+      assert.equal(this.$('.values .value').length, 1, 'it adds the value');
+      assert.equal(this.$('input').val(), '', 'it clears the input');
       assert.ok(this.$('.btn-primary[disabled]').length, "it is disabled again");
+      assert.equal(this.get('values'), 'eviltrout', 'it appends the value');
     });
 
     click('.value .btn-small');
@@ -28,3 +27,41 @@ componentTest('functionality', {
     });
   }
 });
+
+componentTest('with string delimited values', {
+  template: '{{value-list values=valueString}}',
+  setup() {
+    this.set('valueString', "hello\nworld");
+  },
+
+  test(assert) {
+    assert.equal(this.$('.values .value').length, 2);
+
+    fillIn('input', 'eviltrout');
+    click('.btn-primary');
+
+    andThen(() => {
+      assert.equal(this.$('.values .value').length, 3);
+      assert.equal(this.get('valueString'), "hello\nworld\neviltrout");
+    });
+  }
+});
+
+componentTest('with array values', {
+  template: '{{value-list values=valueArray inputType="array"}}',
+  setup() {
+    this.set('valueArray', ['abc', 'def']);
+  },
+
+  test(assert) {
+    assert.equal(this.$('.values .value').length, 2);
+
+    fillIn('input', 'eviltrout');
+    click('.btn-primary');
+
+    andThen(() => {
+      assert.equal(this.$('.values .value').length, 3);
+      assert.deepEqual(this.get('valueArray'), ['abc', 'def', 'eviltrout']);
+    });
+  }
+});