@ApplicationScoped CDI bean and @PersistenceContext - is this safe?

I'm pretty sure that in this case CDI does not create a contextual proxy for the entity manager. After all, what scope would it be in? You may want something akin to a hypothetical @ThreadScoped or just @RequestScoped, but @PersistenceContext is not a CDI annotation and CDI does not modify its semantics.

So what's happening here is the Java EE 6 platform "managed bean" injection, which is similar to injecting the entity manager in a Servlet. Both cases give you an instance that is not thread-safe to use directly.

It looks like it's safe to use with @Stateless, for instance - but I'm not sure if that's because of the way @Stateless works, or because of something intrinsic to @PersistenceContext itself.

It's because of the way @Stateless works. Every request (call) to a method on a stateless bean is routed by the container to a unique instance. The container guarantees that no two threads are ever active in the same bean.

With CDI you can get a similar effect per request by encapsulating the entity manager in a request scoped bean and injecting that into the application scoped one:

import javax.enterprise.context.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@RequestScoped
public class EntityManagerProvider {

    @PersistenceContext
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }

}

Inject this into the bean where you previously injected the entity manager:

@Named
@ApplicationScoped
public class DAO {

   @Inject
   private EntityManagerProvider entityManagerProvider;

}

This will give you a unique entity manager per request. You can easily turn this into a producer method as well, so you won't have to call getEntityManager() on the injected provider.