TL;DR: Gson can't use Pair because there is no a way to instantiate it (at least Gson is aware of: unless you tell Gson to use Pair.of).
Sorry to say but you have a few issues with your solution.
- Don't get bound to 
ArrayList at the declaration site where you can use List. 
- Extending 
Parameters from ArrayList is rather a bad choice (is ArrayList that special? what if you want LinkedList in the future? what if you need a Set instead? which set?) -- prefer aggregation and encapsulate the collection. 
Pair can be replaced with Map.Entry -- use the most generalized type as possible (similar to the previous item).
- Suprisingly, using a 
List for such pairs/entries may be better than using a Map (what if there's a need to store multiple keys in multimap fashion?) 
 
- Gson, unfortunately, won't let you serialize/deserialize 
Object easily because there is no way to reconstruct the original object from the JSON (how should Gson know which class to deserialize with whereas there are tens thousand classes? which one is preferrable? why pay for heuristics or baking in type tags right into JSON to let Gson the original object class (including parameterization if possible)?) -- see some more comments on a similar issue at Why GSON fails to convert Object when it's a field of another Object?. 
One of possible ways to make it work with Gson is both migrating to string-string pairs (so that Gson could know how to make a JSON roundtrip for both keys and values) and writing a pair-aware type adapter factory.
final class PairTypeAdapterFactory
        implements TypeAdapterFactory {
    private static final TypeAdapterFactory instance = new PairTypeAdapterFactory();
    private PairTypeAdapterFactory() {
    }
    static TypeAdapterFactory getInstance() {
        return instance;
    }
    @Override
    @Nullable
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        if ( !Pair.class.isAssignableFrom(typeToken.getRawType()) ) {
            return null;
        }
        final ParameterizedType parameterizedType = (ParameterizedType) typeToken.getType();
        final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        final TypeAdapter<Pair<Object, Object>> pairTypeAdapter = resolveTypeAdapter(gson, actualTypeArguments[0], actualTypeArguments[1]);
        @SuppressWarnings("unchecked")
        final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) pairTypeAdapter;
        return typeAdapter;
    }
    private <L, R> TypeAdapter<Pair<L, R>> resolveTypeAdapter(final Gson gson, final Type leftType, final Type rightType) {
        @SuppressWarnings("unchecked")
        final TypeAdapter<L> leftTypeAdapter = (TypeAdapter<L>) gson.getDelegateAdapter(this, TypeToken.get(leftType));
        @SuppressWarnings("unchecked")
        final TypeAdapter<R> rightTypeAdapter = (TypeAdapter<R>) gson.getDelegateAdapter(this, TypeToken.get(rightType));
        return new TypeAdapter<Pair<L, R>>() {
            @Override
            public void write(final JsonWriter out, final Pair<L, R> value)
                    throws IOException {
                out.beginArray();
                leftTypeAdapter.write(out, value.getLeft());
                rightTypeAdapter.write(out, value.getRight());
                out.endArray();
            }
            @Override
            public Pair<L, R> read(final JsonReader in)
                    throws IOException {
                in.beginArray();
                final L left = leftTypeAdapter.read(in);
                final R right = rightTypeAdapter.read(in);
                in.endArray();
                return Pair.of(left, right);
            }
        }
                .nullSafe();
    }
}
The code above is pretty straight-forward and it also uses arrays to pack pairs into because you might want to store duplicate keys and save some space (additionally, a two-element array is most likely a good carrier for pairs).
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@ToString
final class Event {
    String type;
    List<Pair<String, String>> params;
}
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@ToString
final class JsonFile {
    List<Event> events;
}
private static final Gson gson = new GsonBuilder()
        .disableHtmlEscaping()
        .disableInnerClassSerialization()
        .registerTypeAdapterFactory(PairTypeAdapterFactory.getInstance())
        .create();
@Test
public void test() {
    final JsonFile before = new JsonFile();
    final List<Pair<String, String>> params = new ArrayList<>();
    params.add(Pair.of("xyzzy", "is a magic name"));
    params.add(Pair.of("foo", "bar"));
    final Event event = new Event("lispy event", params);
    before.events = new ArrayList<>();
    before.events.add(event);
    final String json = gson.toJson(before, JsonFile.class);
    final JsonFile after = gson.fromJson(json, JsonFile.class);
    Assertions.assertEquals(before, after);
}
The intermediate JSON is as follows:
{
  "events": [
    {
      "type": "lispy event",
      "params": [
        [
          "xyzzy",
          "is a magic name"
        ],
        [
          "foo",
          "bar"
        ]
      ]
    }
  ]
}
Another (somewhat crazy) idea on using Gson is implementing an heuristics type adapter for Object that are annotated with a custom type-use annotation, say, @Heuristics (these kind of annotations came along with Java 8). This would allow you to parameterize the pairs like this: Pair<String, @Heuristics Object>, but as far as I know, Gson is unable to carry type use annotations within type tokens, so type adapters factories can't get them and apply a custom type adapter (caution: implementing such a type adapter for Object, even those that are not annotated, may cause unwanted global effects).
According to your new information on that, I may be implemented like this (without much commentary, but can be reimplemented if there are more another requirements):
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@ToString
final class JsonFile {
    List<Event<?>> events;
}
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@ToString
final class Event<T> {
    String type;
    Map<String, T> params;
}
final class EventTypeAdapterFactory
        implements TypeAdapterFactory {
    private final Map<String, Class<?>> typeMap;
    private EventTypeAdapterFactory(final Map<String, Class<?>> typeMap) {
        this.typeMap = typeMap;
    }
    static TypeAdapterFactory getInstance(final Map<String, Class<?>> typeMap) {
        return new EventTypeAdapterFactory(typeMap);
    }
    @Override
    @Nullable
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        if ( !Event.class.isAssignableFrom(typeToken.getRawType()) ) {
            return null;
        }
        final Map<String, TypeAdapter<?>> typeAdapterMap = typeMap.entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, e -> gson.getDelegateAdapter(this, TypeToken.getParameterized(Map.class, String.class, e.getValue()))));
        final TypeAdapter<Event<?>> typeAdapter = new TypeAdapter<Event<?>>() {
            @Override
            public void write(final JsonWriter out, final Event<?> value)
                    throws IOException {
                out.beginObject();
                out.name("type");
                out.value(value.type);
                out.name("params");
                @Nullable
                @SuppressWarnings("unchecked")
                final TypeAdapter<Object> paramsTypeAdapter = (TypeAdapter<Object>) typeAdapterMap.get(value.type);
                if ( paramsTypeAdapter == null ) {
                    throw new IllegalStateException(value.type + " is not mapped to a specific type");
                }
                paramsTypeAdapter.write(out, value.params);
                out.endObject();
            }
            @Override
            public Event<?> read(final JsonReader in) {
                final JsonObject root = Streams.parse(in)
                        .getAsJsonObject();
                final String type = root.getAsJsonPrimitive("type")
                        .getAsString();
                @Nullable
                @SuppressWarnings("unchecked")
                final TypeAdapter<Object> paramsTypeAdapter = (TypeAdapter<Object>) typeAdapterMap.get(type);
                if ( paramsTypeAdapter == null ) {
                    throw new IllegalStateException(type + " is not mapped to a specific type");
                }
                final JsonObject rawParams = root.getAsJsonObject("params");
                @SuppressWarnings("unchecked")
                final Map<String, ?> params = (Map<String, ?>) paramsTypeAdapter.fromJsonTree(rawParams);
                return new Event<>(type, params);
            }
        }
                .nullSafe();
        @SuppressWarnings("unchecked")
        final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) typeAdapter;
        return castTypeAdapter;
    }
}
public final class EventTypeAdapterFactoryTest {
    private static final Gson gson = new GsonBuilder()
            .disableHtmlEscaping()
            .disableInnerClassSerialization()
            .registerTypeAdapterFactory(EventTypeAdapterFactory.getInstance(ImmutableMap.of("lispy event", String.class)))
            .create();
    @Test
    public void test() {
        final JsonFile before = new JsonFile();
        final Map<String, Object> params = new LinkedHashMap<>();
        params.put("xyzzy", "is a magic name");
        params.put("foo", "bar");
        final Event<Object> event = new Event<>("lispy event", params);
        before.events = new ArrayList<>();
        before.events.add(event);
        final String json = gson.toJson(before, JsonFile.class);
        System.out.println(json);
        final JsonFile after = gson.fromJson(json, JsonFile.class);
        Assertions.assertEquals(before, after);
    }
}
{
  "events": [
    {
      "type": "lispy event",
      "params": {
        "xyzzy": "is a magic name",
        "foo": "bar"
      }
    }
  ]
}