While paving the way to ValueStore, I've greatly simplified
EntityRefs. They are now singletons, and I've resumed referring to
them as Keys, since that's really how they act. This means that a
RequestFactory based app really won't have to any instantiation of its
DTOs beyond calling eval().

They keys also now instance based, and provide accessors to get to
their properties. The result is a lot less reflection code server
side.

I haven't yet done checkstyle fixes, just want to get this up where it
can be looked at.

Review at http://gwt-code-reviews.appspot.com/243801

Review by: amitmanjhi@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7750 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/eclipse.README b/bikeshed/eclipse.README
index be52ce2..4bcdab2 100644
--- a/bikeshed/eclipse.README
+++ b/bikeshed/eclipse.README
@@ -13,8 +13,10 @@
 # Matches gwtc output in the war directory, e.g. war/com.google.gwt.bikeshed.tree.Tree/
 com.google.gwt.*
 bikeshed/war/expenses/
+bikeshed/war/expensesScaffold/
 bikeshed/war/stocks/
 bikeshed/war/tree/
+bikeshed/war/validation/
 
 * Install the Google Plugin for Eclipse
 * Import trunk/bikeshed/ as a new Java project with existing source
diff --git a/bikeshed/src/com/google/gwt/app/App.gwt.xml b/bikeshed/src/com/google/gwt/app/App.gwt.xml
index 58b1263..b9337b7 100644
--- a/bikeshed/src/com/google/gwt/app/App.gwt.xml
+++ b/bikeshed/src/com/google/gwt/app/App.gwt.xml
@@ -2,6 +2,9 @@
 <!-- Could not determine the version of your GWT SDK; using the module DTD from GWT 1.6.4. You may want to change this. -->
 <!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6.4//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.6.4/distro-source/core/src/gwt-module.dtd">
 <module>
+  <inherits name='com.google.gwt.user.User'/>
+  <inherits name='com.google.gwt.valuestore.ValueStore'/>
+
   <source path="place"/>
   <source path="client"/>
 </module>
\ No newline at end of file
diff --git a/bikeshed/src/com/google/gwt/requestfactory/shared/EntityRef.java b/bikeshed/src/com/google/gwt/requestfactory/shared/EntityKey.java
similarity index 71%
rename from bikeshed/src/com/google/gwt/requestfactory/shared/EntityRef.java
rename to bikeshed/src/com/google/gwt/requestfactory/shared/EntityKey.java
index f4af87f..288388e 100644
--- a/bikeshed/src/com/google/gwt/requestfactory/shared/EntityRef.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/shared/EntityKey.java
@@ -17,17 +17,17 @@
 
 import com.google.gwt.valuestore.shared.Property;
 
+import java.util.Set;
+
 /**
- * Client side proxy object for server side entity.
- *
- * @param <E>
+ * Implemented by client side meta data for server side domain entities.
+ * 
+ * @param <T> type of this entity
  */
-public interface EntityRef<E extends EntityRef<E>> {
+public interface EntityKey<T extends EntityKey<T>> {
+
   /**
-   * @return a reference to a property of this entity
+   * @return the set of properties such entities have
    */
-  <V> FieldRef<E, V> getFieldRef(Property<E, V> property);
-  Object getId();
-  
-  Comparable<?> getVersion();
+  Set<Property<T, ?>> getProperties();
 }
diff --git a/bikeshed/src/com/google/gwt/requestfactory/shared/EntityListRequest.java b/bikeshed/src/com/google/gwt/requestfactory/shared/EntityListRequest.java
index 85cda13..6ce47da 100644
--- a/bikeshed/src/com/google/gwt/requestfactory/shared/EntityListRequest.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/shared/EntityListRequest.java
@@ -25,7 +25,7 @@
  * Implemented by RequestObjects for service methods that return list
  * properties.
  * 
- * @param <E>
+ * @param <E> The type held by the returned list
  */
 public interface EntityListRequest<E> {
   void fire();
diff --git a/bikeshed/src/com/google/gwt/requestfactory/shared/FieldRef.java b/bikeshed/src/com/google/gwt/requestfactory/shared/FieldRef.java
deleted file mode 100644
index 085bc82..0000000
--- a/bikeshed/src/com/google/gwt/requestfactory/shared/FieldRef.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.requestfactory.shared;
-
-import com.google.gwt.valuestore.shared.Property;
-
-/**
- * A pointer to a property value of an Entity.
- *
- * @param <E> Entity
- * @param <V> Value
- */
-public class FieldRef<E extends EntityRef<E>, V> {
-  private final E entity;
-  private final Property<E, V> property;
-
-  public FieldRef(E entity, Property<E, V> property) {
-    assert null != entity;
-    assert null != property;
-    this.entity = entity;
-    this.property = property;
-  }
-
-  // cast is okay b/c of class comparison
-  @SuppressWarnings("unchecked")
-  @Override
-  public boolean equals(Object obj) {
-    if (this == obj) {
-      return true;
-    }
-    if (obj == null) {
-      return false;
-    }
-    if (getClass() != obj.getClass()) {
-      return false;
-    }
-    FieldRef<E, V> other = (FieldRef<E, V>) obj;
-    if (!entity.getId().equals(other.entity.getId())) {
-      return false;
-    }
-    if (!property.equals(other.property)) {
-      return false;
-    }
-    return true;
-  }
-
-  public E getEntity() {
-    return entity;
-  }
-
-  @Override
-  public int hashCode() {
-    final int prime = 31;
-    int result = 1;
-    result = prime * result + entity.getId().hashCode();
-    result = prime * result + property.hashCode();
-    return result;
-  }
-
-  Property<E, V> getProperty() {
-    return property;
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java b/bikeshed/src/com/google/gwt/requestfactory/shared/Id.java
similarity index 71%
rename from bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java
rename to bikeshed/src/com/google/gwt/requestfactory/shared/Id.java
index 8ccbb7a..d934dbb 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/shared/Id.java
@@ -1,24 +1,24 @@
 /*
  * Copyright 2010 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.expenses.shared;
+package com.google.gwt.requestfactory.shared;
 
 /**
- * Implemented by visitors of {@link ExpensesEntity}.
+ * Marks the id {@link com.google.gwt.valuestore.shared.Property Property} of an
+ * {@link EntityKey}.
  */
-public interface ExpensesEntityVisitor {
-  void visit(EmployeeRef employeeRef);
-  void visit(ReportRef reportRef);
+public @interface Id {
+  // TODO prove the servlet will use this info
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java b/bikeshed/src/com/google/gwt/requestfactory/shared/Version.java
similarity index 70%
copy from bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java
copy to bikeshed/src/com/google/gwt/requestfactory/shared/Version.java
index 8ccbb7a..2f20fe9 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/shared/Version.java
@@ -1,24 +1,24 @@
 /*
  * Copyright 2010 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.expenses.shared;
+package com.google.gwt.requestfactory.shared;
 
 /**
- * Implemented by visitors of {@link ExpensesEntity}.
+ * Marks the version {@link com.google.gwt.valuestore.shared.Property Property}
+ * of an {@link EntityKey}.
  */
-public interface ExpensesEntityVisitor {
-  void visit(EmployeeRef employeeRef);
-  void visit(ReportRef reportRef);
+public @interface Version {
+  // TODO prove the servlet will use this info
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/EmployeeList.java b/bikeshed/src/com/google/gwt/sample/expenses/client/EmployeeList.java
index a5370da..040bee0 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/EmployeeList.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/EmployeeList.java
@@ -17,7 +17,7 @@
 
 import com.google.gwt.event.dom.client.ChangeEvent;
 import com.google.gwt.event.dom.client.ChangeHandler;
-import com.google.gwt.sample.expenses.shared.EmployeeRef;
+import com.google.gwt.sample.expenses.shared.EmployeeKey;
 import com.google.gwt.user.client.ui.HasValueList;
 import com.google.gwt.user.client.ui.ListBox;
 import com.google.gwt.valuestore.shared.Values;
@@ -28,22 +28,21 @@
  * Manages the Employee ListBox. This shoudl grow into a proper View, with a
  * corresponding Presenter factored out of {@link Expenses}
  */
-public final class EmployeeList implements HasValueList<Values<EmployeeRef>> {
+public final class EmployeeList implements HasValueList<Values<EmployeeKey>> {
   interface Listener {
-    void onEmployeeSelected(EmployeeRef e);
+    void onEmployeeSelected(Values<EmployeeKey> e);
   }
 
   private final class MyChangeHandler implements ChangeHandler {
     public void onChange(ChangeEvent event) {
       int selectedIndex = listBox.getSelectedIndex();
-      Values<EmployeeRef> values = employeeValues.get(selectedIndex);
-      EmployeeRef e = values.getPropertyHolder();
-      listener.onEmployeeSelected(e);
+      Values<EmployeeKey> values = employeeValues.get(selectedIndex);
+      listener.onEmployeeSelected(values);
     }
   }
 
   private final ListBox listBox;
-  private List<Values<EmployeeRef>> employeeValues;
+  private List<Values<EmployeeKey>> employeeValues;
   private Listener listener;
 
   /**
@@ -56,7 +55,7 @@
   }
 
   public void editValueList(boolean replace, int index,
-      List<Values<EmployeeRef>> newValues) {
+      List<Values<EmployeeKey>> newValues) {
     throw new UnsupportedOperationException();
   }
 
@@ -64,12 +63,12 @@
     this.listener = listener;
   }
 
-  public void setValueList(List<Values<EmployeeRef>> newValues) {
+  public void setValueList(List<Values<EmployeeKey>> newValues) {
     this.employeeValues = newValues;
     listBox.clear();
     for (int i = 0; i < employeeValues.size(); i++) {
-      Values<EmployeeRef> values = employeeValues.get(i);
-      listBox.addItem(values.get(EmployeeRef.DISPLAY_NAME));
+      Values<EmployeeKey> values = employeeValues.get(i);
+      listBox.addItem(values.get(EmployeeKey.get().getDisplayName()));
     }
   }
 
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/EntityList.java b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityList.java
index baa6faf..8b60eb8 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/EntityList.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityList.java
@@ -15,7 +15,7 @@
  */
 package com.google.gwt.sample.expenses.client;
 
-import com.google.gwt.requestfactory.shared.EntityRef;
+import com.google.gwt.requestfactory.shared.EntityKey;
 import com.google.gwt.user.client.ui.HasValueList;
 import com.google.gwt.valuestore.shared.Property;
 import com.google.gwt.valuestore.shared.Values;
@@ -28,7 +28,7 @@
  * 
  * @param <E> the type of entity listed
  */
-public class EntityList<E extends EntityRef<E>> implements
+public class EntityList<E extends EntityKey<E>> implements
     HasValueList<Values<E>> {
   protected final EntityListView view;
   protected final List<Property<E, ?>> properties;
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/Expenses.java b/bikeshed/src/com/google/gwt/sample/expenses/client/Expenses.java
index 4b91e19..45142e7 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/Expenses.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/Expenses.java
@@ -18,8 +18,8 @@
 import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.sample.expenses.gen.ExpenseRequestFactoryImpl;
-import com.google.gwt.sample.expenses.shared.EmployeeRef;
-import com.google.gwt.sample.expenses.shared.ReportRef;
+import com.google.gwt.sample.expenses.shared.EmployeeKey;
+import com.google.gwt.sample.expenses.shared.ReportKey;
 import com.google.gwt.user.client.ui.RootLayoutPanel;
 import com.google.gwt.valuestore.client.ValuesImpl;
 import com.google.gwt.valuestore.shared.Values;
@@ -54,8 +54,8 @@
     
     shell.setListener(new Shell.Listener() {
       public void setFirstPurpose(String purpose) {
-        ValuesImpl<ReportRef> reportValues = (ValuesImpl<ReportRef>) shell.getValues().get(0);
-        reportValues.setString(ReportRef.PURPOSE, purpose);
+        ValuesImpl<ReportKey> reportValues = (ValuesImpl<ReportKey>) shell.getValues().get(0);
+        reportValues.setString(ReportKey.get().getPurpose(), purpose);
         List<Values<?>> deltaValueStore = new ArrayList<Values<?>>();
         deltaValueStore.add(reportValues);
         
@@ -64,17 +64,17 @@
     });
 
     employees.setListener(new EmployeeList.Listener() {
-      public void onEmployeeSelected(EmployeeRef e) {
+      public void onEmployeeSelected(Values<EmployeeKey> e) {
         requestFactory.reportRequest().//
-        findReportsByEmployee(e.getFieldRef(EmployeeRef.ID)).//
-        forProperty(ReportRef.CREATED).//
-        forProperty(ReportRef.PURPOSE).//
+        findReportsByEmployee(e.getRef(EmployeeKey.get().getId())).//
+        forProperty(ReportKey.get().getCreated()).//
+        forProperty(ReportKey.get().getPurpose()).//
         to(shell).//
         fire();
       }
     });
 
     requestFactory.employeeRequest().findAllEmployees().forProperty(
-        EmployeeRef.DISPLAY_NAME).forProperty(EmployeeRef.USER_NAME).to(employees).fire();
+        EmployeeKey.get().getDisplayName()).forProperty(EmployeeKey.get().getUserName()).to(employees).fire();
   }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java b/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java
index 6ce367f..1556bd0 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java
@@ -19,9 +19,9 @@
 import com.google.gwt.app.place.PlaceChanged;
 import com.google.gwt.sample.expenses.client.place.EntityListPlace;
 import com.google.gwt.sample.expenses.client.place.Places;
-import com.google.gwt.sample.expenses.shared.EmployeeRef;
+import com.google.gwt.sample.expenses.shared.EmployeeKey;
 import com.google.gwt.sample.expenses.shared.ExpenseRequestFactory;
-import com.google.gwt.sample.expenses.shared.ReportRef;
+import com.google.gwt.sample.expenses.shared.ReportKey;
 import com.google.gwt.user.client.ui.SimplePanel;
 import com.google.gwt.valuestore.shared.Property;
 
@@ -36,9 +36,9 @@
 
   private final SimplePanel panel;
   private final TableEntityListView entitiesView;
-  private final List<Property<ReportRef, ?>> reportColumns;
+  private final List<Property<ReportKey, ?>> reportColumns;
   private final ExpenseRequestFactory requests;
-  private final List<Property<EmployeeRef, ?>> employeeColumns;
+  private final List<Property<EmployeeKey, ?>> employeeColumns;
 
   /**
    * @param shell
@@ -51,13 +51,13 @@
     this.entitiesView = entitiesView;
     this.requests = requests;
 
-    employeeColumns = new ArrayList<Property<EmployeeRef, ?>>();
-    employeeColumns.add(EmployeeRef.USER_NAME);
-    employeeColumns.add(EmployeeRef.DISPLAY_NAME);
+    employeeColumns = new ArrayList<Property<EmployeeKey, ?>>();
+    employeeColumns.add(EmployeeKey.get().getUserName());
+    employeeColumns.add(EmployeeKey.get().getDisplayName());
 
-    reportColumns = new ArrayList<Property<ReportRef, ?>>();
-    reportColumns.add(ReportRef.CREATED);
-    reportColumns.add(ReportRef.PURPOSE);
+    reportColumns = new ArrayList<Property<ReportKey, ?>>();
+    reportColumns.add(ReportKey.get().getCreated());
+    reportColumns.add(ReportKey.get().getPurpose());
   }
 
   public void onPlaceChanged(PlaceChanged event) {
@@ -74,12 +74,12 @@
     }
 
     if (newPlace == Places.EMPLOYEE_LIST) {
-      EntityList<EmployeeRef> list = new EntityList<EmployeeRef>("Employees",
+      EntityList<EmployeeKey> list = new EntityList<EmployeeKey>("Employees",
           entitiesView, employeeColumns);
       requests.employeeRequest().findAllEmployees().forProperties(
           employeeColumns).to(list).fire();
     } else if (newPlace == Places.REPORT_LIST) {
-      EntityList<ReportRef> list = new EntityList<ReportRef>("Reports",
+      EntityList<ReportKey> list = new EntityList<ReportKey>("Reports",
           entitiesView, reportColumns);
       requests.reportRequest().findAllReports().forProperties(reportColumns).to(
           list).fire();
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/Shell.java b/bikeshed/src/com/google/gwt/sample/expenses/client/Shell.java
index 67b02a8..d399383 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/Shell.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/Shell.java
@@ -25,7 +25,7 @@
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.i18n.client.DateTimeFormat;
-import com.google.gwt.sample.expenses.shared.ReportRef;
+import com.google.gwt.sample.expenses.shared.ReportKey;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
 import com.google.gwt.uibinder.client.UiHandler;
@@ -45,7 +45,7 @@
  * UI shell for expenses sample app. A horrible clump of stuff that should be
  * refactored into proper MVP pieces.
  */
-public class Shell extends Composite implements HasValueList<Values<ReportRef>> {
+public class Shell extends Composite implements HasValueList<Values<ReportKey>> {
   interface Listener {
     void setFirstPurpose(String purpose);
   }
@@ -69,18 +69,18 @@
   TextBox purpose;
   @UiField
   Button save;
-  private List<Values<ReportRef>> values;
+  private List<Values<ReportKey>> values;
 
   public Shell() {
     initWidget(uiBinder.createAndBindUi(this));
   }
 
   public void editValueList(boolean replace, int index,
-      List<Values<ReportRef>> newValues) {
+      List<Values<ReportKey>> newValues) {
     throw new UnsupportedOperationException();
   }
 
-  public List<Values<ReportRef>> getValues() {
+  public List<Values<ReportKey>> getValues() {
     return values;
   }
   
@@ -99,7 +99,7 @@
     this.listener = listener;
   }
   
-  public void setValueList(List<Values<ReportRef>> newValues) {
+  public void setValueList(List<Values<ReportKey>> newValues) {
     this.values = newValues;
     int r = 1; // skip header
     NodeList<TableRowElement> tableRows = table.getRows();
@@ -108,10 +108,10 @@
     purpose.setEnabled(enabled);
     save.setEnabled(enabled);
     for (int i = 0; i < newValues.size(); i++) {
-      Values<ReportRef> valueRow = newValues.get(i);
+      Values<ReportKey> valueRow = newValues.get(i);
 
       if (i == 0) {
-        purpose.setText(valueRow.get(ReportRef.PURPOSE));
+        purpose.setText(valueRow.get(ReportKey.get().getPurpose()));
       }
       if (r < tableRows.getLength()) {
         reuseRow(r, tableRows, valueRow);
@@ -119,7 +119,7 @@
         TableRowElement tableRow = Document.get().createTRElement();
 
         TableCellElement tableCell = Document.get().createTDElement();
-        tableCell.setInnerText(renderDate(valueRow, ReportRef.CREATED));
+        tableCell.setInnerText(renderDate(valueRow, ReportKey.get().getCreated()));
         tableRow.appendChild(tableCell);
 
         tableCell = Document.get().createTDElement();
@@ -127,7 +127,7 @@
         tableRow.appendChild(tableCell);
 
         tableCell = Document.get().createTDElement();
-        tableCell.setInnerText(valueRow.get(ReportRef.PURPOSE));
+        tableCell.setInnerText(valueRow.get(ReportKey.get().getPurpose()));
         tableRow.appendChild(tableCell);
 
         table.appendChild(tableRow);
@@ -153,11 +153,11 @@
    * @param valueRow
    */
   private void reuseRow(int r, NodeList<TableRowElement> tableRows,
-      Values<ReportRef> valueRow) {
+      Values<ReportKey> valueRow) {
     TableRowElement tableRow = tableRows.getItem(r);
     NodeList<TableCellElement> tableCells = tableRow.getCells();
 
-    // tableCells.getItem(0).setInnerText(valueRow.get(Report.CREATED).toString());
-    tableCells.getItem(2).setInnerText(valueRow.get(ReportRef.PURPOSE));
+    // tableCells.getItem(0).setInnerText(valueRow.get(Report.instance().CREATED).toString());
+    tableCells.getItem(2).setInnerText(valueRow.get(ReportKey.get().getPurpose()));
   }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EditEntityPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EditEntityPlace.java
deleted file mode 100644
index 33961f0..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EditEntityPlace.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.client.place;
-
-import com.google.gwt.sample.expenses.shared.ExpensesEntity;
-
-/**
- * 
- */
-public class EditEntityPlace extends EntityPlace {
-
-  /**
-   * @param entityRef The entity to edit
-   */
-  public EditEntityPlace(ExpensesEntity<?> entityRef) {
-    super(entityRef);
-  }
-  
-  public void accept(ExpensesScaffoldPlaceVisitor visitor) {
-    visitor.visit(this);
-  }
-
-  public <T> T accept(ExpensesScaffoldPlaceFilter<T> filter) {
-    return filter.filter(this);
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityDetailsPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityDetailsPlace.java
deleted file mode 100644
index d54128b..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityDetailsPlace.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.client.place;
-
-import com.google.gwt.sample.expenses.shared.ExpensesEntity;
-
-/**
- * 
- */
-public class EntityDetailsPlace extends EntityPlace {
-
-  /**
-   * @param entityRef The entity to edit
-   */
-  public EntityDetailsPlace(ExpensesEntity<?> entityRef) {
-    super(entityRef);
-  }
-
-  public void accept(ExpensesScaffoldPlaceVisitor visitor) {
-    visitor.visit(this);
-  }
-
-  public <T> T accept(ExpensesScaffoldPlaceFilter<T> filter) {
-    return filter.filter(this);
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityPlace.java
deleted file mode 100644
index 011b37c..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityPlace.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.client.place;
-
-import com.google.gwt.sample.expenses.shared.ExpensesEntity;
-
-/**
- * A place in the app focused on a particular {@link ExpensesEntity}
- */
-public abstract class EntityPlace extends ExpensesScaffoldPlace {
-  private final ExpensesEntity<?> entityRef;
-
-  public EntityPlace(ExpensesEntity<?> entityRef) {
-    assert null != entityRef;
-    this.entityRef = entityRef;
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if (this == obj)
-      return true;
-    if (obj == null)
-      return false;
-    if (getClass() != obj.getClass())
-      return false;
-    EntityPlace other = (EntityPlace) obj;
-    return entityRef.getId().equals(other.entityRef.getId());
-  }
-
-  public ExpensesEntity<?> getEntity() {
-    return entityRef;
-  }
-
-  @Override
-  public int hashCode() {
-    final int prime = 31;
-    int result = 1;
-    result = prime * result + entityRef.getId().hashCode();
-    return result;
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceFilter.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceFilter.java
index 15849da..b2e15fb 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceFilter.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceFilter.java
@@ -23,17 +23,17 @@
  */
 public interface ExpensesScaffoldPlaceFilter<T> {
 
-  /**
-   * @param editEntityPlace
-   * @return
-   */
-  T filter(EditEntityPlace editEntityPlace);
-
-  /**
-   * @param entityDetailsPlace
-   * @return
-   */
-  T filter(EntityDetailsPlace entityDetailsPlace);
+//  /**
+//   * @param editEntityPlace
+//   * @return
+//   */
+//  T filter(EditEntityPlace editEntityPlace);
+//
+//  /**
+//   * @param entityDetailsPlace
+//   * @return
+//   */
+//  T filter(EntityDetailsPlace entityDetailsPlace);
 
   /**
    * @param entityListPlace
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceVisitor.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceVisitor.java
index 096c2e2..55e4108 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceVisitor.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceVisitor.java
@@ -20,15 +20,15 @@
  */
 public interface ExpensesScaffoldPlaceVisitor {
 
-  /**
-   * @param editEntityPlace
-   */
-  void visit(EditEntityPlace editEntityPlace);
-
-  /**
-   * @param entityDetailsPlace
-   */
-  void visit(EntityDetailsPlace entityDetailsPlace);
+//  /**
+//   * @param editEntityPlace
+//   */
+//  void visit(EditEntityPlace editEntityPlace);
+//
+//  /**
+//   * @param entityDetailsPlace
+//   */
+//  void visit(EntityDetailsPlace entityDetailsPlace);
 
   /**
    * @param entityListPlace
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/Places.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/Places.java
index c1e44c1..e7ee68d 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/Places.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/Places.java
@@ -15,8 +15,6 @@
  */
 package com.google.gwt.sample.expenses.client.place;
 
-import com.google.gwt.sample.expenses.shared.ExpensesEntity;
-
 import java.util.LinkedHashMap;
 import java.util.Map;
 
@@ -40,11 +38,11 @@
     return navPlaces;
   }
 
-  public EntityDetailsPlace getDetailsPlaceFor(ExpensesEntity<?> e) {
-    return new EntityDetailsPlace(e);
-  }
-
-  public EditEntityPlace getEditPlaceFor(ExpensesEntity<?> e) {
-    return new EditEntityPlace(e);
-  }
+//  public EntityDetailsPlace getDetailsPlaceFor(ExpensesEntity<?> e) {
+//    return new EntityDetailsPlace(e);
+//  }
+//
+//  public EditEntityPlace getEditPlaceFor(ExpensesEntity<?> e) {
+//    return new EditEntityPlace(e);
+//  }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gen/EmployeeRequestImpl.java b/bikeshed/src/com/google/gwt/sample/expenses/gen/EmployeeRequestImpl.java
index a464655..7234314 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gen/EmployeeRequestImpl.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gen/EmployeeRequestImpl.java
@@ -22,7 +22,7 @@
 import com.google.gwt.http.client.RequestException;
 import com.google.gwt.http.client.Response;
 import com.google.gwt.requestfactory.shared.EntityListRequest;
-import com.google.gwt.sample.expenses.shared.EmployeeRef;
+import com.google.gwt.sample.expenses.shared.EmployeeKey;
 import com.google.gwt.sample.expenses.shared.ExpenseRequestFactory;
 import com.google.gwt.user.client.ui.HasValueList;
 import com.google.gwt.valuestore.client.ValuesImpl;
@@ -32,26 +32,32 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * "Generated" from static methods of {@link com.google.gwt.sample.expenses.server.domain.Employee}.
  */
 public class EmployeeRequestImpl implements ExpenseRequestFactory.EmployeeRequest {
 
-  @SuppressWarnings("unused")
-  public EmployeeRequestImpl(ValueStore values) {
+  @SuppressWarnings("unused") // TODO next step is to use it
+  private ValueStore valueStore;
+
+  public EmployeeRequestImpl(ValueStore valueStore) {
+    this.valueStore = valueStore;
   }
 
-  public EntityListRequest<EmployeeRef> findAllEmployees() {
-    return new EntityListRequest<EmployeeRef>() {
-      private HasValueList<Values<EmployeeRef>> watcher;
+  public EntityListRequest<EmployeeKey> findAllEmployees() {
+    
+    
+    return new EntityListRequest<EmployeeKey>() {
+      private HasValueList<Values<EmployeeKey>> watcher;
+      private Set<Property<EmployeeKey, ?>> properties = new HashSet<Property<EmployeeKey, ?>>();
 
       public void fire() {
-
-        // TODO: need someway to track that this request has been issued so that
-        // we don't issue another request that arrives while we are waiting for
-        // the response.
+        // TODO: accumulate and batch fire requests, e.g. once batch per event loop
+        // TODO: cache and short circuit find requests
         RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,
             "/expenses/data?methodName=" + MethodName.FIND_ALL_EMPLOYEES.name());
         builder.setCallback(new RequestCallback() {
@@ -63,17 +69,19 @@
           public void onResponseReceived(Request request, Response response) {
             if (200 == response.getStatusCode()) {
               String text = response.getText();
-              JsArray<ValuesImpl<EmployeeRef>> valueArray = ValuesImpl.arrayFromJson(text);
-              // Handy for FireBug snooping
-//              Document.get().getBody().setPropertyJSO("foo", valueArray);
-              List<Values<EmployeeRef>> valueList = new ArrayList<Values<EmployeeRef>>(
+//              DeltaValueStore deltaStore = valueStore.edit();
+              JsArray<ValuesImpl<EmployeeKey>> valueArray = ValuesImpl.arrayFromJson(text);
+              List<Values<EmployeeKey>> valueList = new ArrayList<Values<EmployeeKey>>(
                   valueArray.length());
               for (int i = 0; i < valueArray.length(); i++) {
-                ValuesImpl<EmployeeRef> values = valueArray.get(i);
-                values.setPropertyHolder(new EmployeeRef(values.get(EmployeeRef.ID),
-                    values.get(EmployeeRef.VERSION)));
+                ValuesImpl<EmployeeKey> values = valueArray.get(i);
+                values.setPropertyHolder(EmployeeKey.get());
+//                deltaStore.setValue(propertyHolder, properties, values);
                 valueList.add(values);
               }
+
+//              valueStore.subscribe(watcher, valueList, properties);
+//              deltaStore.commit();
               watcher.setValueList(valueList);
             } else {
               // shell.error.setInnerText(SERVER_ERROR + " ("
@@ -88,25 +96,24 @@
           // shell.error.setInnerText(SERVER_ERROR + " (" + e.getMessage() +
           // ")");
         }
-
-        // values.subscribe(watcher, future, properties);
       }
-      
-      public EntityListRequest<EmployeeRef> forProperties(
-          Collection<Property<EmployeeRef, ?>> properties) {
-        for (Property<EmployeeRef, ?> property : properties) {
+
+      public EntityListRequest<EmployeeKey> forProperties(
+          Collection<Property<EmployeeKey, ?>> properties) {
+        for (Property<EmployeeKey, ?> property : properties) {
           forProperty(property);
         }
         return this;
       }
 
-      public EntityListRequest<EmployeeRef> forProperty(
-          Property<EmployeeRef, ?> property) {
+      public EntityListRequest<EmployeeKey> forProperty(
+          Property<EmployeeKey, ?> property) {
+        properties.add(property);
         return this;
       }
 
-      public EntityListRequest<EmployeeRef> to(
-          HasValueList<Values<EmployeeRef>> watcher) {
+      public EntityListRequest<EmployeeKey> to(
+          HasValueList<Values<EmployeeKey>> watcher) {
         this.watcher = watcher;
         return this;
       }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gen/ExpenseRequestFactoryImpl.java b/bikeshed/src/com/google/gwt/sample/expenses/gen/ExpenseRequestFactoryImpl.java
index d9dc5d9..0862aa1 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gen/ExpenseRequestFactoryImpl.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gen/ExpenseRequestFactoryImpl.java
@@ -61,9 +61,7 @@
     public <T, V> void subscribe(HasValueList<Values<T>> watcher,
         T propertyOwner, Set<Property<T, ?>> properties) {
       // TODO Auto-generated method stub
-    }
-
-  };
+    }};
 
   public EmployeeRequest employeeRequest() {
     return new EmployeeRequestImpl(values);
@@ -94,9 +92,9 @@
 
       public void fire() {
 
-        // TODO: need some way to track that this request has been issued so
-        // that we don't issue another request that arrives while we are
-        // waiting for the response.
+        // TODO: need some way to track that this request has been issued so that
+        // we don't issue another request that arrives while we are waiting for
+        // the response.
         RequestBuilder builder = new RequestBuilder(RequestBuilder.POST,
             "/expenses/data?methodName=" + MethodName.SYNC.name());
 
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gen/ReportRequestImpl.java b/bikeshed/src/com/google/gwt/sample/expenses/gen/ReportRequestImpl.java
index 591c2bf..a6ca12b 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gen/ReportRequestImpl.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gen/ReportRequestImpl.java
@@ -22,13 +22,13 @@
 import com.google.gwt.http.client.RequestException;
 import com.google.gwt.http.client.Response;
 import com.google.gwt.requestfactory.shared.EntityListRequest;
-import com.google.gwt.requestfactory.shared.FieldRef;
-import com.google.gwt.sample.expenses.shared.EmployeeRef;
+import com.google.gwt.sample.expenses.shared.EmployeeKey;
 import com.google.gwt.sample.expenses.shared.ExpenseRequestFactory;
-import com.google.gwt.sample.expenses.shared.ReportRef;
+import com.google.gwt.sample.expenses.shared.ReportKey;
 import com.google.gwt.user.client.ui.HasValueList;
 import com.google.gwt.valuestore.client.ValuesImpl;
 import com.google.gwt.valuestore.shared.Property;
+import com.google.gwt.valuestore.shared.ValueRef;
 import com.google.gwt.valuestore.shared.ValueStore;
 import com.google.gwt.valuestore.shared.Values;
 
@@ -48,12 +48,12 @@
   public ReportRequestImpl(ValueStore values) {
   }
 
-  public EntityListRequest<ReportRef> findReportsByEmployee(
-      final FieldRef<EmployeeRef, String> id) {
+  public EntityListRequest<ReportKey> findReportsByEmployee(
+      final ValueRef<EmployeeKey, String> id) {
 
-    return new EntityListRequest<ReportRef>() {
-      Set<Property<ReportRef, ?>> properties = new HashSet<Property<ReportRef, ?>>();
-      private HasValueList<Values<ReportRef>> watcher;
+    return new EntityListRequest<ReportKey>() {
+      Set<Property<ReportKey, ?>> properties = new HashSet<Property<ReportKey, ?>>();
+      private HasValueList<Values<ReportKey>> watcher;
 
       public void fire() {
 
@@ -64,7 +64,7 @@
             RequestBuilder.GET,
             "/expenses/data?methodName="
                 + MethodName.FIND_REPORTS_BY_EMPLOYEE.name()
-                + UrlParameterManager.getUrlFragment(new Object[] {id.getEntity().getId()}));
+                + UrlParameterManager.getUrlFragment(new Object[] {id.get()}));
         builder.setCallback(new RequestCallback() {
 
           public void onError(Request request, Throwable exception) {
@@ -74,15 +74,12 @@
           public void onResponseReceived(Request request, Response response) {
             if (200 == response.getStatusCode()) {
               String text = response.getText();
-              JsArray<ValuesImpl<ReportRef>> valueArray = ValuesImpl.arrayFromJson(text);
-              List<Values<ReportRef>> valueList = new ArrayList<Values<ReportRef>>(
+              JsArray<ValuesImpl<ReportKey>> valueArray = ValuesImpl.arrayFromJson(text);
+              List<Values<ReportKey>> valueList = new ArrayList<Values<ReportKey>>(
                   valueArray.length());
               for (int i = 0; i < valueArray.length(); i++) {
-                ValuesImpl<ReportRef> values = valueArray.get(i);
-                String id2 = values.get(ReportRef.ID);
-                Integer version = values.get(ReportRef.VERSION);
-                values.setPropertyHolder(new ReportRef(id2,
-                    version));
+                ValuesImpl<ReportKey> values = valueArray.get(i);
+                values.setPropertyHolder(ReportKey.get());
                 valueList.add(values);
               }
               watcher.setValueList(valueList);
@@ -103,30 +100,30 @@
         // values.subscribe(watcher, future, properties);
       }
 
-      public EntityListRequest<ReportRef> forProperties(
-          Collection<Property<ReportRef, ?>> properties) {
-        for (Property<ReportRef, ?> property : properties) {
+      public EntityListRequest<ReportKey> forProperties(
+          Collection<Property<ReportKey, ?>> properties) {
+        for (Property<ReportKey, ?> property : properties) {
           forProperty(property);
         }
         return this;
       }
 
-      public EntityListRequest<ReportRef> forProperty(Property<ReportRef, ?> property) {
+      public EntityListRequest<ReportKey> forProperty(Property<ReportKey, ?> property) {
         properties.add(property);
         return this;
       }
 
 
-      public EntityListRequest<ReportRef> to(HasValueList<Values<ReportRef>> watcher) {
+      public EntityListRequest<ReportKey> to(HasValueList<Values<ReportKey>> watcher) {
         this.watcher = watcher;
         return this;
       }
     };
   }
 
-  public EntityListRequest<ReportRef> findAllReports() {
-    return new EntityListRequest<ReportRef>() {
-      private HasValueList<Values<ReportRef>> watcher;
+  public EntityListRequest<ReportKey> findAllReports() {
+    return new EntityListRequest<ReportKey>() {
+      private HasValueList<Values<ReportKey>> watcher;
 
       public void fire() {
 
@@ -144,15 +141,14 @@
           public void onResponseReceived(Request request, Response response) {
             if (200 == response.getStatusCode()) {
               String text = response.getText();
-              JsArray<ValuesImpl<ReportRef>> valueArray = ValuesImpl.arrayFromJson(text);
+              JsArray<ValuesImpl<ReportKey>> valueArray = ValuesImpl.arrayFromJson(text);
               // Handy for FireBug snooping
 //              Document.get().getBody().setPropertyJSO("foo", valueArray);
-              List<Values<ReportRef>> valueList = new ArrayList<Values<ReportRef>>(
+              List<Values<ReportKey>> valueList = new ArrayList<Values<ReportKey>>(
                   valueArray.length());
               for (int i = 0; i < valueArray.length(); i++) {
-                ValuesImpl<ReportRef> values = valueArray.get(i);
-                values.setPropertyHolder(new ReportRef(values.get(ReportRef.ID),
-                    values.get(ReportRef.VERSION)));
+                ValuesImpl<ReportKey> values = valueArray.get(i);
+                values.setPropertyHolder(ReportKey.get());
                 valueList.add(values);
               }
               watcher.setValueList(valueList);
@@ -173,21 +169,21 @@
         // values.subscribe(watcher, future, properties);
       }
       
-      public EntityListRequest<ReportRef> forProperties(
-          Collection<Property<ReportRef, ?>> properties) {
-        for (Property<ReportRef, ?> property : properties) {
+      public EntityListRequest<ReportKey> forProperties(
+          Collection<Property<ReportKey, ?>> properties) {
+        for (Property<ReportKey, ?> property : properties) {
           forProperty(property);
         }
         return this;
       }
 
-      public EntityListRequest<ReportRef> forProperty(
-          Property<ReportRef, ?> property) {
+      public EntityListRequest<ReportKey> forProperty(
+          Property<ReportKey, ?> property) {
         return this;
       }
 
-      public EntityListRequest<ReportRef> to(
-          HasValueList<Values<ReportRef>> watcher) {
+      public EntityListRequest<ReportKey> to(
+          HasValueList<Values<ReportKey>> watcher) {
         this.watcher = watcher;
         return this;
       }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java b/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java
index fcf7424..f0d6e06 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java
@@ -15,10 +15,13 @@
  */
 package com.google.gwt.sample.expenses.server;
 
+import com.google.gwt.requestfactory.shared.EntityKey;
 import com.google.gwt.sample.expenses.gen.MethodName;
 import com.google.gwt.sample.expenses.gen.UrlParameterManager;
 import com.google.gwt.sample.expenses.server.domain.Report;
 import com.google.gwt.sample.expenses.server.domain.Storage;
+import com.google.gwt.sample.expenses.shared.ReportKey;
+import com.google.gwt.valuestore.shared.Property;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -27,7 +30,6 @@
 import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -49,11 +51,12 @@
   private static final Set<String> PROPERTY_SET = new HashSet<String>();
   static {
     for (String str : new String[] {
-        "ID", "VERSION", "DISPLAY_NAME", "USER_NAME", "PURPOSE", "CREATED"}) {
+        "id", "version", "displayName", "userName", "purpose", "created"}) {
       PROPERTY_SET.add(str);
     }
   }
 
+  @SuppressWarnings("unchecked")
   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
       throws IOException {
@@ -105,7 +108,7 @@
       throw new IllegalArgumentException(e);
     } catch (NoSuchMethodException e) {
       throw new IllegalArgumentException(e);
-    }
+    } 
   }
 
   @Override
@@ -132,12 +135,6 @@
    * @param resultObject object returned by a 'get' method, must be of type
    *          List<? extends Entity>
    * @return the JSONArray
-   * @throws ClassNotFoundException
-   * @throws InvocationTargetException
-   * @throws IllegalAccessException
-   * @throws NoSuchMethodException
-   * @throws JSONException
-   * @throws SecurityException
    */
   private JSONArray getJsonArray(List<?> resultList)
       throws ClassNotFoundException, SecurityException, JSONException,
@@ -148,14 +145,19 @@
     }
     Object firstElement = resultList.get(0);
     Class<?> entityClass = firstElement.getClass();
-    Class<?> entityRefClass = Class.forName("com.google.gwt.sample.expenses.shared."
-        + entityClass.getSimpleName() + "Ref");
+
+    // TODO This brittle mapping from server name to client name is why we need
+    // the custom RequestFactory interface to serve as the config
+    Class<?> entityKeyClass = Class.forName("com.google.gwt.sample.expenses.shared."
+        + entityClass.getSimpleName() + "Key");
+
+    EntityKey<?> key = (EntityKey<?>) entityKeyClass.getMethod("get").invoke(null);
     for (Object entityElement : resultList) {
       JSONObject jsonObject = new JSONObject();
-      for (Field field : entityRefClass.getFields()) {
-        // TODO: perhaps get the property names from javax.persistence.Id fields
-        if (isProperty(field) && requestedProperty(field)) {
-          String propertyName = getPropertyName(field);
+      for (Property<?, ?> p : key.getProperties()) {
+
+        if (requestedProperty(p)) {
+          String propertyName = p.getName();
           jsonObject.put(propertyName, getPropertyValue(entityElement,
               propertyName));
         }
@@ -181,42 +183,24 @@
   /**
    * Returns methodName corresponding to the propertyName that can be invoked on
    * an {@link Entity} object.
-   *
-   * Example: "USER_NAME" returns "getUserName". "VERSION" returns "getVersion"
+   * 
+   * Example: "userName" returns "getUserName". "version" returns "getVersion"
    */
   private String getMethodNameFromPropertyName(String propertyName) {
-    assert propertyName != null;
-    assert propertyName.equals(propertyName.toUpperCase());
-    StringBuffer methodName = new StringBuffer("get");
-    int index = 0;
-    int length = propertyName.length();
-    while (index < length) {
-      int underscore = propertyName.indexOf('_', index);
-      if (underscore == -1) {
-        underscore = length;
-      }
-      methodName.append(propertyName.charAt(index));
-      methodName.append(propertyName.substring(index + 1, underscore).toLowerCase());
-      index = underscore + 1; // skip the '_' character.
+    if (propertyName == null) {
+      throw new NullPointerException("propertyName must not be null");
     }
-    return methodName.toString();
-  }
 
-  /**
-   * returns the property name.
-   */
-  private String getPropertyName(Field field) {
-    return field.getName();
+    StringBuffer methodName = new StringBuffer("get");
+    methodName.append(propertyName.substring(0, 1).toUpperCase());
+    methodName.append(propertyName.substring(1));
+    return methodName.toString();
   }
 
   /**
    * @param entityElement
    * @param property
    * @return
-   * @throws NoSuchMethodException
-   * @throws SecurityException
-   * @throws InvocationTargetException
-   * @throws IllegalAccessException
    */
   private Object getPropertyValue(Object entityElement, String propertyName)
       throws SecurityException, NoSuchMethodException, IllegalAccessException,
@@ -238,26 +222,13 @@
   }
 
   /**
-   * @param field
-   * @return
-   */
-  private boolean isProperty(Field field) {
-    int modifiers = field.getModifiers();
-    if (!Modifier.isStatic(modifiers) || !Modifier.isFinal(modifiers)
-        || !Modifier.isPublic(modifiers)) {
-      return false;
-    }
-    return "Property".equals(field.getType().getSimpleName());
-  }
-
-  /**
    * returns true if the property has been requested. TODO: fix this hack.
-   *
-   * @param field the field of entity ref
+   * 
+   * @param p the field of entity ref
    * @return has the property value been requested
    */
-  private boolean requestedProperty(Field field) {
-    return PROPERTY_SET.contains(field.getName());
+  private boolean requestedProperty(Property<?, ?> p) {
+    return PROPERTY_SET.contains(p.getName());
   }
 
   /**
@@ -281,12 +252,10 @@
       int length = reportArray.length();
       if (length > 0) {
         JSONObject report = reportArray.getJSONObject(0);
-        Report r = Report.findReport(report.getLong(com.google.gwt.sample.expenses.shared.ReportRef.ID.getName()));
-        r.setPurpose(report.getString(com.google.gwt.sample.expenses.shared.ReportRef.PURPOSE.getName()));
+        Report r = Report.findReport(report.getLong(ReportKey.get().getId().getName()));
+        r.setPurpose(report.getString(ReportKey.get().getPurpose().getName()));
         r = Storage.INSTANCE.persist(r);
-        report.put(
-            com.google.gwt.sample.expenses.shared.ReportRef.VERSION.getName(),
-            r.getVersion());
+        report.put(ReportKey.get().getVersion().getName(), r.getVersion());
         JSONArray returnArray = new JSONArray();
         // TODO: don't echo back everything.
         returnArray.put(report);
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeKey.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeKey.java
new file mode 100644
index 0000000..59b11cd
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeKey.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.shared;
+
+import com.google.gwt.requestfactory.shared.Id;
+import com.google.gwt.requestfactory.shared.LongString;
+import com.google.gwt.requestfactory.shared.ServerType;
+import com.google.gwt.requestfactory.shared.EntityKey;
+import com.google.gwt.requestfactory.shared.Version;
+import com.google.gwt.valuestore.shared.Property;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * "Generated" proxy of
+ * {@link com.google.gwt.sample.expenses.server.domain.Employee domain.Employee}
+ * .
+ */
+@ServerType(com.google.gwt.sample.expenses.server.domain.Employee.class)
+public class EmployeeKey implements EntityKey<EmployeeKey> {
+  private static EmployeeKey instance;
+
+  public static EmployeeKey get() {
+    if (instance == null) {
+      instance = new EmployeeKey();
+    }
+    return instance;
+  }
+
+  private final Property<EmployeeKey, String> id = new Property<EmployeeKey, String>(
+      String.class, "id");
+
+  private final Property<EmployeeKey, String> displayName = new Property<EmployeeKey, String>(
+      String.class, "displayName");
+
+  private final Property<EmployeeKey, EmployeeKey> supervisor = new Property<EmployeeKey, EmployeeKey>(
+      EmployeeKey.class, "superVisor");
+
+  private final Property<EmployeeKey, String> userName = new Property<EmployeeKey, String>(
+      String.class, "userName");
+
+  private final Property<EmployeeKey, Integer> version = new Property<EmployeeKey, Integer>(
+      Integer.class, "version");
+
+  private final Set<Property<EmployeeKey, ?>> properties = new HashSet<Property<EmployeeKey, ?>>();
+
+  EmployeeKey() {
+    properties.add(id);
+    properties.add(displayName);
+    properties.add(supervisor);
+    properties.add(userName);
+    properties.add(version);
+  }
+
+  public Property<EmployeeKey, String> getDisplayName() {
+    return displayName;
+  }
+
+  @LongString
+  @Id
+  public Property<EmployeeKey, String> getId() {
+    return id;
+  }
+
+  public Set<Property<EmployeeKey, ?>> getProperties() {
+    return properties;
+  }
+
+  public Property<EmployeeKey, EmployeeKey> getSupervisor() {
+    return supervisor;
+  }
+
+  public Property<EmployeeKey, String> getUserName() {
+    return userName;
+  }
+  
+  @Version
+  public Property<EmployeeKey, Integer> getVersion() {
+    return version;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeRef.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeRef.java
deleted file mode 100644
index 3c844e0..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeRef.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.shared;
-
-import com.google.gwt.requestfactory.shared.FieldRef;
-import com.google.gwt.requestfactory.shared.LongString;
-import com.google.gwt.requestfactory.shared.ServerType;
-import com.google.gwt.valuestore.shared.Property;
-
-/**
- * "Generated" proxy of {@link com.google.gwt.sample.expenses.server.domain.Employee
- * domain.Employee}.
- */
-@ServerType(com.google.gwt.sample.expenses.server.domain.Employee.class)
-public class EmployeeRef implements ExpensesEntity<EmployeeRef> {
-
-  @LongString
-  public static final Property<EmployeeRef, String> ID = new Property<EmployeeRef, String>(
-      EmployeeRef.class, String.class, "ID");
-
-  public static final Property<EmployeeRef, String> DISPLAY_NAME = new Property<EmployeeRef, String>(
-      EmployeeRef.class, String.class, "DISPLAY_NAME");
-  public static final Property<EmployeeRef, EmployeeRef> SUPERVISOR = new Property<EmployeeRef, EmployeeRef>(
-      EmployeeRef.class, EmployeeRef.class, "SUPERVISOR");
-
-  public static final Property<EmployeeRef, String> USER_NAME = new Property<EmployeeRef, String>(
-      EmployeeRef.class, String.class, "USER_NAME");
-
-  public static final Property<EmployeeRef, Integer> VERSION = new Property<EmployeeRef, Integer>(
-      EmployeeRef.class, Integer.class, "VERSION");
-
-  private final String id;
-  private final Integer version;
-
-  public EmployeeRef(String id, Integer version) {
-    this.id = id;
-    this.version = version;
-  }
-
-  public <T> T accept(ExpensesEntityFilter<T> filter) {
-    return filter.filter(this);
-  }
-
-  public void accept(ExpensesEntityVisitor visitor) {
-    visitor.visit(this);
-  }
-
-  public <V> FieldRef<EmployeeRef, V> getFieldRef(Property<EmployeeRef, V> property) {
-    return new FieldRef<EmployeeRef, V>(this, property);
-  }
-
-  public String getId() {
-    return id;
-  }
-
-  public Integer getVersion() {
-    return version;
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpenseRequestFactory.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpenseRequestFactory.java
index 5de9fa7..6d874e1 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpenseRequestFactory.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpenseRequestFactory.java
@@ -16,10 +16,10 @@
 package com.google.gwt.sample.expenses.shared;
 
 import com.google.gwt.requestfactory.shared.EntityListRequest;
-import com.google.gwt.requestfactory.shared.FieldRef;
 import com.google.gwt.requestfactory.shared.LongString;
 import com.google.gwt.requestfactory.shared.RequestFactory;
 import com.google.gwt.valuestore.shared.DeltaValueStore;
+import com.google.gwt.valuestore.shared.ValueRef;
 
 /**
  * Generated for the service methods of
@@ -35,7 +35,7 @@
     /**
      * @return a request object
      */
-    EntityListRequest<EmployeeRef> findAllEmployees();
+    EntityListRequest<EmployeeKey> findAllEmployees();
   }
 
   /**
@@ -46,13 +46,13 @@
     /**
      * @return a request object
      */
-    EntityListRequest<ReportRef> findReportsByEmployee(
-        @LongString FieldRef<EmployeeRef, String> id);
+    EntityListRequest<ReportKey> findReportsByEmployee(
+        @LongString ValueRef<EmployeeKey, String> id);
 
     /**
      * @return a request object
      */
-    EntityListRequest<ReportRef> findAllReports();
+    EntityListRequest<ReportKey> findAllReports();
   }
 
   /**
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntity.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntity.java
deleted file mode 100644
index 273455b..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.shared;
-
-import com.google.gwt.requestfactory.shared.EntityRef;
-
-/**
- * Implemented by entities of the {@link ExpensesRequestFactory}.
- * 
- * @param <E> the type of this entity
- */
-public interface ExpensesEntity<E extends ExpensesEntity<E>>
-    extends EntityRef<E> {
-  
-  void accept(ExpensesEntityVisitor visitor);
-
-  <T> T accept(ExpensesEntityFilter<T> filter);
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityFilter.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityFilter.java
deleted file mode 100644
index e761285..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityFilter.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.shared;
-
-/**
- * Implemented by filters of {@link ExpensesEntity}.
- * 
- * @param <T> the type to filter to
- */
-public interface ExpensesEntityFilter<T> {
-  T filter(EmployeeRef employeeRef);
-
-  T filter(ReportRef reportRef);
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportKey.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportKey.java
new file mode 100644
index 0000000..b2b3193
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportKey.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.shared;
+
+import com.google.gwt.requestfactory.shared.Id;
+import com.google.gwt.requestfactory.shared.LongString;
+import com.google.gwt.requestfactory.shared.ServerType;
+import com.google.gwt.requestfactory.shared.EntityKey;
+import com.google.gwt.requestfactory.shared.Version;
+import com.google.gwt.valuestore.shared.Property;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * "Generated" proxy of
+ * {@link com.google.gwt.sample.expenses.server.domain.Report domain.Report}.
+ */
+@ServerType(com.google.gwt.sample.expenses.server.domain.Report.class)
+public class ReportKey implements EntityKey<ReportKey> {
+  private static ReportKey instance;
+
+  public static ReportKey get() {
+    if (instance == null) {
+      instance = new ReportKey();
+    }
+    return instance;
+  }
+
+  private final Property<ReportKey, String> id = new Property<ReportKey, String>(
+      String.class, "id");
+
+  private final Property<ReportKey, Integer> version = new Property<ReportKey, Integer>(
+      Integer.class, "version");
+
+  private final Property<ReportKey, Date> created = new Property<ReportKey, Date>(
+      Date.class, "created");
+
+  private final Property<ReportKey, String> purpose = new Property<ReportKey, String>(
+      String.class, "purpose");
+
+  private final Set<Property<ReportKey, ?>> properties = new HashSet<Property<ReportKey, ?>>();
+
+  ReportKey() {
+    properties.add(id);
+    properties.add(version);
+    properties.add(created);
+    properties.add(purpose);
+  }
+
+  public Property<ReportKey, Date> getCreated() {
+    return created;
+  }
+
+  @LongString
+  @Id
+  public Property<ReportKey, String> getId() {
+    return id;
+  }
+
+  public Set<Property<ReportKey, ?>> getProperties() {
+    return properties;
+  }
+
+  public Property<ReportKey, String> getPurpose() {
+    return purpose;
+  }
+
+  @Version
+  public Property<ReportKey, Integer> getVersion() {
+    return version;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportRef.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportRef.java
deleted file mode 100644
index 907a489..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportRef.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.shared;
-
-import com.google.gwt.requestfactory.shared.FieldRef;
-import com.google.gwt.requestfactory.shared.LongString;
-import com.google.gwt.requestfactory.shared.ServerType;
-import com.google.gwt.valuestore.shared.Property;
-
-import java.util.Date;
-
-/**
- * "Generated" proxy of
- * {@link com.google.gwt.sample.expenses.server.domain.Report domain.Report}.
- */
-@ServerType(com.google.gwt.sample.expenses.server.domain.Report.class)
-public class ReportRef implements ExpensesEntity<ReportRef> {
-
-  @LongString
-  public static final Property<ReportRef, String> ID = new Property<ReportRef, String>(
-      ReportRef.class, String.class, "ID");
-
-  public static final Property<ReportRef, Integer> VERSION = new Property<ReportRef, Integer>(
-      ReportRef.class, Integer.class, "VERSION");
-
-  public static final Property<ReportRef, Date> CREATED = new Property<ReportRef, Date>(
-      ReportRef.class, Date.class, "CREATED");
-
-  public static final Property<ReportRef, String> PURPOSE = new Property<ReportRef, String>(
-      ReportRef.class, String.class, "PURPOSE");
-
-  private final String id;
-  private final Integer version;
-
-  public ReportRef(String id, Integer version) {
-    this.id = id;
-    this.version = version;
-  }
-
-  public <T> T accept(ExpensesEntityFilter<T> filter) {
-    return filter.filter(this);
-  }
-
-  public void accept(ExpensesEntityVisitor visitor) {
-    visitor.visit(this);
-  }
-
-  public <V> FieldRef<ReportRef, V> getFieldRef(Property<ReportRef, V> property) {
-    return new FieldRef<ReportRef, V>(this, property);
-  }
-
-  public String getId() {
-    return id;
-  }
-
-  public Integer getVersion() {
-    return version;
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/valuestore/client/ValuesImpl.java b/bikeshed/src/com/google/gwt/valuestore/client/ValuesImpl.java
index 47038e6..33131bf 100644
--- a/bikeshed/src/com/google/gwt/valuestore/client/ValuesImpl.java
+++ b/bikeshed/src/com/google/gwt/valuestore/client/ValuesImpl.java
@@ -19,6 +19,7 @@
 import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.core.client.JsArray;
 import com.google.gwt.valuestore.shared.Property;
+import com.google.gwt.valuestore.shared.ValueRef;
 import com.google.gwt.valuestore.shared.Values;
 
 import java.util.Date;
@@ -61,11 +62,15 @@
   }
 
   public native T getPropertyHolder() /*-{
-    return this.propertyHolder;
+    return this['__key'];
   }-*/;
 
-  public native void setPropertyHolder(T propertyHolder) /*-{
-    this.propertyHolder = propertyHolder;
+  public <V> ValueRef<T, V> getRef(Property<T, V> property) {
+    return new ValueRef<T, V>(this, property);
+  }
+
+  public native void setPropertyHolder(T key) /*-{
+    this['__key'] = key;
   }-*/;
 
   public native void setString(Property<T, String> property, String value) /*-{
@@ -78,7 +83,7 @@
    */
   public native String toJson() /*-{
     var replacer = function(key, value) {
-      if (key == 'propertyHolder') {
+      if (key == '__key') {
         return;
       }
       return value;
diff --git a/bikeshed/src/com/google/gwt/valuestore/shared/Property.java b/bikeshed/src/com/google/gwt/valuestore/shared/Property.java
index 75a4f0a..2c2f87b 100644
--- a/bikeshed/src/com/google/gwt/valuestore/shared/Property.java
+++ b/bikeshed/src/com/google/gwt/valuestore/shared/Property.java
@@ -22,24 +22,18 @@
  * @param <V> type of the property
  */
 public class Property<T, V> {
-  private final Class<T> propertyHolderType;
+  // TODO Is this actually useful as a class, or do we need
+  // the EntityKey instance? Either way, need a getter for it.
+  // Should become clear as ValueStore is implemented
   private final Class<V> valueType;
   private final String name;
 
-  public Property(Class<T> propertyHolderType, Class<V> valueType, String name) {
-    this.propertyHolderType = propertyHolderType;
+  public Property(Class<V> valueType, String name) {
     this.valueType = valueType;
     this.name = name;
   }
 
   /**
-   * @return the entityType
-   */
-  public Class<T> getEntityType() {
-    return propertyHolderType;
-  }
-
-  /**
    * @return the name
    */
   public String getName() {
diff --git a/bikeshed/src/com/google/gwt/valuestore/shared/ValueRef.java b/bikeshed/src/com/google/gwt/valuestore/shared/ValueRef.java
new file mode 100644
index 0000000..79e69a7
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/valuestore/shared/ValueRef.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.valuestore.shared;
+
+/**
+ * A pointer to a value.
+ *
+ * @param <K> Key type
+ * @param <V> Value type
+ */
+public class ValueRef<K, V> {
+  private final Values<K> values;
+  private final Property<K, V> property;
+
+  public ValueRef(Values<K> values, Property<K, V> property) {
+    assert null != values;
+    assert null != property;
+
+    this.values = values;
+    this.property = property;
+  }
+
+  public V get() {
+    return values.get(property);
+  }
+
+  Property<K, V> getProperty() {
+    return property;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/valuestore/shared/Values.java b/bikeshed/src/com/google/gwt/valuestore/shared/Values.java
index 82c8bcb..d3d7827 100644
--- a/bikeshed/src/com/google/gwt/valuestore/shared/Values.java
+++ b/bikeshed/src/com/google/gwt/valuestore/shared/Values.java
@@ -21,7 +21,11 @@
  * @param <T> value type.
  */
 public interface Values<T> {
+  // TODO At the moment this isn't actually used. If it stays unused
+  // once ValueStore is in place, delete it
   T getPropertyHolder();
 
   <V, P extends Property<T, V>> V get(P property);
+  
+  <V> ValueRef<T, V> getRef(Property<T, V> property);
 }