A cleaner approach might be
final Iterable<Entry<String, Integer>> iterable = getIterable();
final Gson gson = new Gson();
final JsonArray jsonArray = new JsonArray();
for (final Entry<String, Integer> entry : iterable) {
    final JsonElement jsonElement = gson.toJsonTree(entry);
    jsonElement.getAsJsonObject().remove("hash");
    jsonArray.add(jsonElement);
}
Or a Stream version, which I love
StreamSupport.stream(iterable.spliterator(), false)
             .map(gson::toJsonTree)
             .map(JsonElement::getAsJsonObject)
             .peek(obj -> obj.remove("hash"))
             .collect(of(
                     JsonArray::new,
                     (array, obj) -> array.add(obj),
                     (output, toMerge) -> {
                         output.addAll(toMerge);
                         return output;
                     }
             ));
output: [{"key":"1","value":1},{"key":"2","value":2}]
TL;DR: you need a custom TypeAdapterFactory and a custom TypeAdapter.
See this method on TypeAdapters
public static <TT> TypeAdapterFactory newFactory(
    final TypeToken<TT> type, final TypeAdapter<TT> typeAdapter) {
  return new TypeAdapterFactory() {
    @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
    @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
      return typeToken.equals(type) ? (TypeAdapter<T>) typeAdapter : null;
    }
  };
}

Without a custom TypeAdapterFactory
typeToken.equals(type)
returns false, and even a custom TypeAdapter<Entry> isn't used.
The problem lies here, at ReflectiveTypeAdapterFactory#write
@Override public void write(JsonWriter out, T value) throws IOException {
  if (value == null) {
    out.nullValue();
    return;
  }
  out.beginObject();
  try {
    for (BoundField boundField : boundFields.values()) {
      if (boundField.writeField(value)) {
        out.name(boundField.name);
        boundField.write(out, value);
      }
    }
  } catch (IllegalAccessException e) {
    throw new AssertionError(e);
  }
  out.endObject();
}
and at ReflectiveTypeAdapterFactory#getBoundFields
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
  Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
  if (raw.isInterface()) {
    return result;
  }
Gson is recognizing the input Entry (Class<?> raw parameter) as 
interface Map.Entry<K, V> { ... }
Therefore
if (raw.isInterface())
yield true, and an empty boundFields LinkedHashMap is returned.
Thus, here
for (BoundField boundField : boundFields.values()) { ... }
the loop isn't executed, and no values are extracted and written with
boundField.write(...)