You can use closures to store state in Erlang, but generally state is kept by passing it through to further function calls.
I would say this makes Erlang mostly have explicit state, rather than saying Erlang is stateless.
Ets is implemented in C as global mutable state, but you could implement it in Erlang as a process per table (and a process to hold the list of tables) with no loss of functionality. You would send messages to fetch data or update data, etc. It's a performance and memory efficiency optimization to do it with C, of course.