public static InventoryEvent<?> from(Action<?, ?> action, Object object) {
    if (object == null) {
      throw new IllegalArgumentException("object == null");
    }

    if (action == null) {
      throw new IllegalArgumentException("action == null");
    }

    if (object instanceof Tenant) {
      return new TenantEvent(action.asEnum(), (Tenant) object);
    } else if (object instanceof Environment) {
      return new EnvironmentEvent(action.asEnum(), (Environment) object);
    } else if (object instanceof Feed) {
      return new FeedEvent(action.asEnum(), (Feed) object);
    } else if (object instanceof Metric) {
      return new MetricEvent(action.asEnum(), (Metric) object);
    } else if (object instanceof MetricType) {
      return new MetricTypeEvent(action.asEnum(), (MetricType) object);
    } else if (object instanceof Resource) {
      return new ResourceEvent(action.asEnum(), (Resource) object);
    } else if (object instanceof ResourceType) {
      return new ResourceTypeEvent(action.asEnum(), (ResourceType) object);
    } else if (object instanceof Relationship) {
      return new RelationshipEvent(action.asEnum(), (Relationship) object);
    } else if (object instanceof DataEntity) {
      return new DataEntityEvent(action.asEnum(), (DataEntity) object);
    } else if (object instanceof Action.Update) {
      @SuppressWarnings("unchecked")
      AbstractElement<?, AbstractElement.Update> updated =
          (AbstractElement<?, AbstractElement.Update>) ((Action.Update) object).getOriginalEntity();

      updated.update().with((AbstractElement.Update) ((Action.Update) object).getUpdate());

      // TODO should we instead send the whole update object? No time for that now, but it'd be
      // preferable I think
      return from(action, updated);
    } else {
      throw new IllegalArgumentException("Unsupported entity type: " + object.getClass());
    }
  }