How to run a scheduled job every 15 minutes?

Jobs cannot be scheduled in increments smaller than one hour. Please read the documentation to learn about how you can schedule jobs that run in more complex patterns than the GUI allows.

In Apex, you can schedule four jobs to every hour, staggered 15 minutes apart:

System.schedule('Scheduled Job 1', '0 0 * * * ?', new ScheduledClass());
System.schedule('Scheduled Job 2', '0 15 * * * ?', new ScheduledClass());
System.schedule('Scheduled Job 3', '0 30 * * * ?', new ScheduledClass());
System.schedule('Scheduled Job 4', '0 45 * * * ?', new ScheduledClass());

@Christian is correct, but you can combine all that into a single line to be more efficient.

System.schedule('Scheduled Job 1', '0 0,15,30,45 * * * ?', new ScheduledClass());

Edit

It appears I was incorrect, you can only use comma separated lists for units hours or larger. Minutes and seconds does not support a comma separated list, so it appears you are stuck with either scheduling 4 jobs like below, or getting creative by scheduling a following job in the Finish() method of your batch class.

System.schedule('Scheduled Job 1', '0 0 * * * ?', new ScheduledClass());
System.schedule('Scheduled Job 2', '0 15 * * * ?', new ScheduledClass());
System.schedule('Scheduled Job 3', '0 30 * * * ?', new ScheduledClass());
System.schedule('Scheduled Job 4', '0 45 * * * ?', new ScheduledClass());

I've been playing around with something like this to achieve periodic execution of an operation with granularity as low as 1 or 2 minutes. It's a class that implements the Schedulable interface. In its "execute" method, it simply reschedules a new instance of itself some time in the future (specified by the "intervalMinutes" parameter, then aborts its currently scheduled instance, and invokes a future method or launches a batch job to do the actual work. The nice thing about this approach is that it doesn't require multiple scheduled Apex jobs (there's never more than one scheduled at a time). It seems to be working quite well. See any potential drawbacks to this approach?

global without sharing class JobRunner implements Schedulable {
    Integer intervalMinutes;
    public JobRunner(Integer intervalMinutes) {
        this.intervalMinutes = intervalMinutes;
    }
    public void execute(SchedulableContext sc) {
        // Re-schedule ourself to run again in "intervalMinutes" time
        DateTime now  = DateTime.now();
        DateTime nextRunTime = now.addMinutes(intervalMinutes);
        String cronString = '' + nextRunTime.second() + ' ' + nextRunTime.minute() + ' ' + 
            nextRunTime.hour() + ' ' + nextRunTime.day() + ' ' + 
            nextRunTime.month() + ' ? ' + nextRunTime.year(); 
        System.schedule(JobRunner.class.getName() + '-' + now.format(), cronString, new JobRunner(intervalMinutes));
        // Abort the current job
        Id jobId = sc.getTriggerId();
        System.abortJob(jobId);     
        // Launch a batch job or call a future method to do the actual work
        Database.executeBatch(new SomeBatchJob());
    }
}